kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling
@ 2020-12-10 14:28 Andre Przywara
  2020-12-10 14:28 ` [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch() Andre Przywara
                   ` (21 more replies)
  0 siblings, 22 replies; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

At the moment we use two separate code paths to handle exits for
KVM_EXIT_IO (ioport.c) and KVM_EXIT_MMIO (mmio.c), even though they
are semantically very similar. Because the trap handler callback routine
is different, devices need to decide on one conduit or need to provide
different handler functions for both of them.

This is not only unnecessary code duplication, but makes switching
devices from I/O port to MMIO a tedious task, even though there is no
real difference between the two, especially on ARM and PowerPC.

For ARM we aim at providing a flexible memory layout, and also have
trouble with the UART and RTC device overlapping with the PCI I/O area,
so it seems indicated to tackle this once and for all.

The first three patches do some cleanup, to simplify things later.

Patch 04/21 lays the groundwork, by extending mmio.c to be able to also
register I/O port trap handlers, using the same callback prototype as
we use for MMIO.

The next 14 patches then convert devices that use the I/O port
interface over to the new joint interface. This requires to rework
the trap handler routine to adhere to the same prototype as the existing
MMIO handlers. For most devices this is done in two steps: a first to
introduce the reworked handler routine, and a second to switch to the new
joint registration routine. For some devices the first step is trivial,
so it's done in one patch.

Patch 19/21 then retires the old I/O port interface, by removing ioport.c
and friends.

The final two patches switch the UART and the RTC device over to register
on the MMIO "bus", when running on ARM or arm64. This changes the
addresses to be at 16MB, so they are not in the PCI I/O area anymore.

Admittedly this goal can be achieved much simpler, by just having the
first three patches, and some more changes and ifdef's in the last two,
but I figured it would be good to clean up the I/O port mess for good.

Please have a look and comment!

Cheers,
Andre

Andre Przywara (21):
  ioport: Remove ioport__setup_arch()
  hw/serial: Use device abstraction for FDT generator function
  ioport: Retire .generate_fdt_node functionality
  mmio: Extend handling to include ioport emulation
  hw/i8042: Clean up data types
  hw/i8042: Refactor trap handler
  hw/i8042: Switch to new trap handlers
  x86/ioport: Refactor trap handlers
  x86/ioport: Switch to new trap handlers
  hw/rtc: Refactor trap handlers
  hw/rtc: Switch to new trap handler
  hw/vesa: Switch trap handling to use MMIO handler
  hw/serial: Refactor trap handler
  hw/serial: Switch to new trap handlers
  vfio: Refactor ioport trap handler
  vfio: Switch to new ioport trap handlers
  virtio: Switch trap handling to use MMIO handler
  pci: Switch trap handling to use MMIO handler
  Remove ioport specific routines
  hw/serial: ARM/arm64: Use MMIO at higher addresses
  hw/rtc: ARM/arm64: Use MMIO at higher addresses

 Makefile             |   1 -
 arm/ioport.c         |   5 -
 hw/i8042.c           |  88 ++++++----------
 hw/rtc.c             |  91 ++++++++---------
 hw/serial.c          | 166 +++++++++++++++++++-----------
 hw/vesa.c            |  19 +---
 include/kvm/i8042.h  |   1 -
 include/kvm/ioport.h |  25 -----
 include/kvm/kvm.h    |  42 +++++++-
 ioport.c             | 235 -------------------------------------------
 mips/kvm.c           |   5 -
 mmio.c               |  59 +++++++++--
 pci.c                |  82 +++++----------
 powerpc/ioport.c     |   6 --
 vfio/core.c          |  50 ++++-----
 virtio/pci.c         |  42 ++------
 x86/ioport.c         | 106 +++++++++----------
 17 files changed, 385 insertions(+), 638 deletions(-)
 delete mode 100644 ioport.c

-- 
2.17.1


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

* [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-10 17:44   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function Andre Przywara
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Since x86 had a special need for registering tons of special I/O ports,
we had an ioport__setup_arch() callback, to allow each architecture
to do the same. As it turns out no one uses it beside x86, so we remove
that unnecessary abstraction.

The generic function was registered via a device_base_init() call, so
we just do the same for the x86 specific function only, and can remove
the unneeded ioport__setup_arch().

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 arm/ioport.c         |  5 -----
 include/kvm/ioport.h |  1 -
 ioport.c             | 28 ----------------------------
 mips/kvm.c           |  5 -----
 powerpc/ioport.c     |  6 ------
 x86/ioport.c         | 25 ++++++++++++++++++++++++-
 6 files changed, 24 insertions(+), 46 deletions(-)

diff --git a/arm/ioport.c b/arm/ioport.c
index 2f0feb9a..24092c9d 100644
--- a/arm/ioport.c
+++ b/arm/ioport.c
@@ -1,11 +1,6 @@
 #include "kvm/ioport.h"
 #include "kvm/irq.h"
 
-int ioport__setup_arch(struct kvm *kvm)
-{
-	return 0;
-}
-
 void ioport__map_irq(u8 *irq)
 {
 	*irq = irq__alloc_line();
diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
index 039633f7..d0213541 100644
--- a/include/kvm/ioport.h
+++ b/include/kvm/ioport.h
@@ -35,7 +35,6 @@ struct ioport_operations {
 							    enum irq_type));
 };
 
-int ioport__setup_arch(struct kvm *kvm);
 void ioport__map_irq(u8 *irq);
 
 int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
diff --git a/ioport.c b/ioport.c
index 844a832d..667e8386 100644
--- a/ioport.c
+++ b/ioport.c
@@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
 	return 0;
 }
 
-static void ioport__unregister_all(void)
-{
-	struct ioport *entry;
-	struct rb_node *rb;
-	struct rb_int_node *rb_node;
-
-	rb = rb_first(&ioport_tree);
-	while (rb) {
-		rb_node = rb_int(rb);
-		entry = ioport_node(rb_node);
-		ioport_unregister(&ioport_tree, entry);
-		rb = rb_first(&ioport_tree);
-	}
-}
-
 static const char *to_direction(int direction)
 {
 	if (direction == KVM_EXIT_IO_IN)
@@ -220,16 +205,3 @@ out:
 
 	return !kvm->cfg.ioport_debug;
 }
-
-int ioport__init(struct kvm *kvm)
-{
-	return ioport__setup_arch(kvm);
-}
-dev_base_init(ioport__init);
-
-int ioport__exit(struct kvm *kvm)
-{
-	ioport__unregister_all();
-	return 0;
-}
-dev_base_exit(ioport__exit);
diff --git a/mips/kvm.c b/mips/kvm.c
index 26355930..e110e5d5 100644
--- a/mips/kvm.c
+++ b/mips/kvm.c
@@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
 		die_perror("KVM_IRQ_LINE ioctl");
 }
 
-int ioport__setup_arch(struct kvm *kvm)
-{
-	return 0;
-}
-
 bool kvm__arch_cpu_supports_vm(void)
 {
 	return true;
diff --git a/powerpc/ioport.c b/powerpc/ioport.c
index 0c188b61..a5cff4ee 100644
--- a/powerpc/ioport.c
+++ b/powerpc/ioport.c
@@ -12,12 +12,6 @@
 
 #include <stdlib.h>
 
-int ioport__setup_arch(struct kvm *kvm)
-{
-	/* PPC has no legacy ioports to set up */
-	return 0;
-}
-
 void ioport__map_irq(u8 *irq)
 {
 }
diff --git a/x86/ioport.c b/x86/ioport.c
index 7ad7b8f3..8c5c7699 100644
--- a/x86/ioport.c
+++ b/x86/ioport.c
@@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
 {
 }
 
-int ioport__setup_arch(struct kvm *kvm)
+static int ioport__setup_arch(struct kvm *kvm)
 {
 	int r;
 
@@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
 
 	return 0;
 }
+dev_base_init(ioport__setup_arch);
+
+static int ioport__remove_arch(struct kvm *kvm)
+{
+	ioport__unregister(kvm, 0x510);
+	ioport__unregister(kvm, 0x402);
+	ioport__unregister(kvm, 0x03D5);
+	ioport__unregister(kvm, 0x03D4);
+	ioport__unregister(kvm, 0x0378);
+	ioport__unregister(kvm, 0x0278);
+	ioport__unregister(kvm, 0x00F0);
+	ioport__unregister(kvm, 0x00ED);
+	ioport__unregister(kvm, IOPORT_DBG);
+	ioport__unregister(kvm, 0x00C0);
+	ioport__unregister(kvm, 0x00A0);
+	ioport__unregister(kvm, 0x0092);
+	ioport__unregister(kvm, 0x0040);
+	ioport__unregister(kvm, 0x0020);
+	ioport__unregister(kvm, 0x0000);
+
+	return 0;
+}
+dev_base_exit(ioport__remove_arch);
-- 
2.17.1


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

* [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
  2020-12-10 14:28 ` [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch() Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-11 12:05   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality Andre Przywara
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

At the moment we use the .generate_fdt_node member of the ioport ops
structure to store the function pointer for the FDT node generator
function. ioport__register() will then put a wrapper and this pointer
into the device header.
The serial device is the only device making use of this special ioport
feature, so let's move this over to using the device header directly.

This will allow us to get rid of this .generate_fdt_node member in the
ops and simplify the code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/serial.c       | 49 +++++++++++++++++++++++++++++++++++++----------
 include/kvm/kvm.h |  2 ++
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/hw/serial.c b/hw/serial.c
index 13c4663e..b0465d99 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -23,6 +23,7 @@
 #define UART_IIR_TYPE_BITS	0xc0
 
 struct serial8250_device {
+	struct device_header	dev_hdr;
 	struct mutex		mutex;
 	u8			id;
 
@@ -53,9 +54,20 @@ struct serial8250_device {
 	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
 	.mcr			= UART_MCR_OUT2,
 
+#ifdef CONFIG_HAS_LIBFDT
+static
+void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
+				  fdt_irq_fn irq_fn);
+#else
+#define serial8250_generate_fdt_node	NULL
+#endif
 static struct serial8250_device devices[] = {
 	/* ttyS0 */
 	[0]	= {
+		.dev_hdr = {
+			.bus_type	= DEVICE_BUS_IOPORT,
+			.data		= serial8250_generate_fdt_node,
+		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 0,
@@ -66,6 +78,10 @@ static struct serial8250_device devices[] = {
 	},
 	/* ttyS1 */
 	[1]	= {
+		.dev_hdr = {
+			.bus_type	= DEVICE_BUS_IOPORT,
+			.data		= serial8250_generate_fdt_node,
+		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 1,
@@ -76,6 +92,10 @@ static struct serial8250_device devices[] = {
 	},
 	/* ttyS2 */
 	[2]	= {
+		.dev_hdr = {
+			.bus_type	= DEVICE_BUS_IOPORT,
+			.data		= serial8250_generate_fdt_node,
+		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 2,
@@ -86,6 +106,10 @@ static struct serial8250_device devices[] = {
 	},
 	/* ttyS3 */
 	[3]	= {
+		.dev_hdr = {
+			.bus_type	= DEVICE_BUS_IOPORT,
+			.data		= serial8250_generate_fdt_node,
+		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 3,
@@ -371,13 +395,14 @@ char *fdt_stdout_path = NULL;
 
 #define DEVICE_NAME_MAX_LEN 32
 static
-void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
-				  void (*generate_irq_prop)(void *fdt,
-							    u8 irq,
-							    enum irq_type))
+void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
+				  fdt_irq_fn irq_fn)
 {
 	char dev_name[DEVICE_NAME_MAX_LEN];
-	struct serial8250_device *dev = ioport->priv;
+	struct serial8250_device *dev = container_of(dev_hdr,
+						     struct serial8250_device,
+						     dev_hdr);
+
 	u64 addr = KVM_IOPORT_AREA + dev->iobase;
 	u64 reg_prop[] = {
 		cpu_to_fdt64(addr),
@@ -395,24 +420,26 @@ void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
 	_FDT(fdt_begin_node(fdt, dev_name));
 	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
-	generate_irq_prop(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
+	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
 	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
 	_FDT(fdt_end_node(fdt));
 }
-#else
-#define serial8250_generate_fdt_node	NULL
 #endif
 
 static struct ioport_operations serial8250_ops = {
 	.io_in			= serial8250_in,
 	.io_out			= serial8250_out,
-	.generate_fdt_node	= serial8250_generate_fdt_node,
 };
 
-static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
+static int serial8250__device_init(struct kvm *kvm,
+				   struct serial8250_device *dev)
 {
 	int r;
 
+	r = device__register(&dev->dev_hdr);
+	if (r < 0)
+		return r;
+
 	ioport__map_irq(&dev->irq);
 	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);
 
@@ -438,6 +465,7 @@ cleanup:
 		struct serial8250_device *dev = &devices[j];
 
 		ioport__unregister(kvm, dev->iobase);
+		device__unregister(&dev->dev_hdr);
 	}
 
 	return r;
@@ -455,6 +483,7 @@ int serial8250__exit(struct kvm *kvm)
 		r = ioport__unregister(kvm, dev->iobase);
 		if (r < 0)
 			return r;
+		device__unregister(&dev->dev_hdr);
 	}
 
 	return 0;
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 53373b08..ee99c28e 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -31,6 +31,8 @@
 	.name = #ext,			\
 	.code = ext
 
+typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);
+
 enum {
 	KVM_VMSTATE_RUNNING,
 	KVM_VMSTATE_PAUSED,
-- 
2.17.1


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

* [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
  2020-12-10 14:28 ` [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch() Andre Przywara
  2020-12-10 14:28 ` [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-11 14:05   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation Andre Przywara
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

The ioport routines support a special way of registering FDT node
generator functions. There is no reason to have this separate from the
already existing way via the device header.

Now that the only user of this special ioport variety has been
transferred, we can retire this code, to simplify ioport handling.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/ioport.h |  4 ----
 ioport.c             | 34 ----------------------------------
 2 files changed, 38 deletions(-)

diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
index d0213541..a61038e2 100644
--- a/include/kvm/ioport.h
+++ b/include/kvm/ioport.h
@@ -29,10 +29,6 @@ struct ioport {
 struct ioport_operations {
 	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
 	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
-	void (*generate_fdt_node)(struct ioport *ioport, void *fdt,
-				  void (*generate_irq_prop)(void *fdt,
-							    u8 irq,
-							    enum irq_type));
 };
 
 void ioport__map_irq(u8 *irq);
diff --git a/ioport.c b/ioport.c
index 667e8386..b98836d3 100644
--- a/ioport.c
+++ b/ioport.c
@@ -56,7 +56,6 @@ static struct ioport *ioport_get(struct rb_root *root, u64 addr)
 /* Called with ioport_lock held. */
 static void ioport_unregister(struct rb_root *root, struct ioport *data)
 {
-	device__unregister(&data->dev_hdr);
 	ioport_remove(root, data);
 	free(data);
 }
@@ -70,30 +69,6 @@ static void ioport_put(struct rb_root *root, struct ioport *data)
 	mutex_unlock(&ioport_lock);
 }
 
-#ifdef CONFIG_HAS_LIBFDT
-static void generate_ioport_fdt_node(void *fdt,
-				     struct device_header *dev_hdr,
-				     void (*generate_irq_prop)(void *fdt,
-							       u8 irq,
-							       enum irq_type))
-{
-	struct ioport *ioport = container_of(dev_hdr, struct ioport, dev_hdr);
-	struct ioport_operations *ops = ioport->ops;
-
-	if (ops->generate_fdt_node)
-		ops->generate_fdt_node(ioport, fdt, generate_irq_prop);
-}
-#else
-static void generate_ioport_fdt_node(void *fdt,
-				     struct device_header *dev_hdr,
-				     void (*generate_irq_prop)(void *fdt,
-							       u8 irq,
-							       enum irq_type))
-{
-	die("Unable to generate device tree nodes without libfdt\n");
-}
-#endif
-
 int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
 {
 	struct ioport *entry;
@@ -107,10 +82,6 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
 		.node		= RB_INT_INIT(port, port + count),
 		.ops		= ops,
 		.priv		= param,
-		.dev_hdr	= (struct device_header) {
-			.bus_type	= DEVICE_BUS_IOPORT,
-			.data		= generate_ioport_fdt_node,
-		},
 		/*
 		 * Start from 0 because ioport__unregister() doesn't decrement
 		 * the reference count.
@@ -123,15 +94,10 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
 	r = ioport_insert(&ioport_tree, entry);
 	if (r < 0)
 		goto out_free;
-	r = device__register(&entry->dev_hdr);
-	if (r < 0)
-		goto out_remove;
 	mutex_unlock(&ioport_lock);
 
 	return port;
 
-out_remove:
-	ioport_remove(&ioport_tree, entry);
 out_free:
 	free(entry);
 	mutex_unlock(&ioport_lock);
-- 
2.17.1


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

* [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (2 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-11 16:10   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 05/21] hw/i8042: Clean up data types Andre Przywara
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

In their core functionality MMIO and I/O port traps are not really
different, yet we still have two totally separate code paths for
handling them. Devices need to decide on one conduit or need to provide
different handler functions for each of them.

Extend the existing MMIO emulation to also cover ioport handlers.
This just adds another RB tree root for holding the I/O port handlers,
but otherwise uses the same tree population and lookup code.
"ioport" or "mmio" just become a flag in the registration function.
Provide wrappers to not break existing users, and allow an easy
transition for the existing ioport handlers.

This also means that ioport handlers now can use the same emulation
callback prototype as MMIO handlers, which means we have to migrate them
over. To allow a smooth transition, we hook up the new I/O emulate
function to the end of the existing ioport emulation code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 include/kvm/kvm.h | 42 +++++++++++++++++++++++++++++----
 ioport.c          |  4 ++--
 mmio.c            | 59 +++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 89 insertions(+), 16 deletions(-)

diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index ee99c28e..14f9d58b 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -27,10 +27,16 @@
 #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
 #endif
 
+#define IOTRAP_BUS_MASK		0xf
+#define IOTRAP_COALESCE		(1U << 4)
+
 #define DEFINE_KVM_EXT(ext)		\
 	.name = #ext,			\
 	.code = ext
 
+struct kvm_cpu;
+typedef void (*mmio_handler_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+				u32 len, u8 is_write, void *ptr);
 typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);
 
 enum {
@@ -113,6 +119,8 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
 void kvm__irq_trigger(struct kvm *kvm, int irq);
 bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
 bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
+bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
+		      int direction, int size, u32 count);
 int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
 int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
 		      enum kvm_mem_type type);
@@ -136,10 +144,36 @@ static inline int kvm__reserve_mem(struct kvm *kvm, u64 guest_phys, u64 size)
 				 KVM_MEM_TYPE_RESERVED);
 }
 
-int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
-				    void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
-				    void *ptr);
-bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
+int __must_check kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 len,
+				      mmio_handler_fn mmio_fn, void *ptr,
+				      unsigned int flags);
+
+static inline
+int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr,
+				    u64 phys_addr_len, bool coalesce,
+				    mmio_handler_fn mmio_fn, void *ptr)
+{
+	return kvm__register_iotrap(kvm, phys_addr, phys_addr_len, mmio_fn, ptr,
+			DEVICE_BUS_MMIO | (coalesce ? IOTRAP_COALESCE : 0));
+}
+static inline
+int __must_check kvm__register_pio(struct kvm *kvm, u16 port, u16 len,
+				   mmio_handler_fn mmio_fn, void *ptr)
+{
+	return kvm__register_iotrap(kvm, port, len, mmio_fn, ptr,
+				    DEVICE_BUS_IOPORT);
+}
+
+bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags);
+static inline bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
+{
+	return kvm__deregister_iotrap(kvm, phys_addr, DEVICE_BUS_MMIO);
+}
+static inline bool kvm__deregister_pio(struct kvm *kvm, u16 port)
+{
+	return kvm__deregister_iotrap(kvm, port, DEVICE_BUS_IOPORT);
+}
+
 void kvm__reboot(struct kvm *kvm);
 void kvm__pause(struct kvm *kvm);
 void kvm__continue(struct kvm *kvm);
diff --git a/ioport.c b/ioport.c
index b98836d3..204d8103 100644
--- a/ioport.c
+++ b/ioport.c
@@ -147,7 +147,8 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
 
 	entry = ioport_get(&ioport_tree, port);
 	if (!entry)
-		goto out;
+		return kvm__emulate_pio(vcpu, port, data, direction,
+					size, count);
 
 	ops	= entry->ops;
 
@@ -162,7 +163,6 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
 
 	ioport_put(&ioport_tree, entry);
 
-out:
 	if (ret)
 		return true;
 
diff --git a/mmio.c b/mmio.c
index cd141cd3..4cce1901 100644
--- a/mmio.c
+++ b/mmio.c
@@ -19,13 +19,14 @@ static DEFINE_MUTEX(mmio_lock);
 
 struct mmio_mapping {
 	struct rb_int_node	node;
-	void			(*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
+	mmio_handler_fn		mmio_fn;
 	void			*ptr;
 	u32			refcount;
 	bool			remove;
 };
 
 static struct rb_root mmio_tree = RB_ROOT;
+static struct rb_root pio_tree = RB_ROOT;
 
 static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
 {
@@ -103,9 +104,9 @@ static void mmio_put(struct kvm *kvm, struct rb_root *root, struct mmio_mapping
 	mutex_unlock(&mmio_lock);
 }
 
-int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
-		       void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
-			void *ptr)
+int kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len,
+			 mmio_handler_fn mmio_fn, void *ptr,
+			 unsigned int flags)
 {
 	struct mmio_mapping *mmio;
 	struct kvm_coalesced_mmio_zone zone;
@@ -127,7 +128,7 @@ int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool c
 		.remove		= false,
 	};
 
-	if (coalesce) {
+	if (flags & IOTRAP_COALESCE) {
 		zone = (struct kvm_coalesced_mmio_zone) {
 			.addr	= phys_addr,
 			.size	= phys_addr_len,
@@ -139,18 +140,27 @@ int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool c
 		}
 	}
 	mutex_lock(&mmio_lock);
-	ret = mmio_insert(&mmio_tree, mmio);
+	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
+		ret = mmio_insert(&pio_tree, mmio);
+	else
+		ret = mmio_insert(&mmio_tree, mmio);
 	mutex_unlock(&mmio_lock);
 
 	return ret;
 }
 
-bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
+bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags)
 {
 	struct mmio_mapping *mmio;
+	struct rb_root *tree;
+
+	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
+		tree = &pio_tree;
+	else
+		tree = &mmio_tree;
 
 	mutex_lock(&mmio_lock);
-	mmio = mmio_search_single(&mmio_tree, phys_addr);
+	mmio = mmio_search_single(tree, phys_addr);
 	if (mmio == NULL) {
 		mutex_unlock(&mmio_lock);
 		return false;
@@ -167,7 +177,7 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
 	 * called mmio_put(). This will trigger use-after-free errors on VCPU0.
 	 */
 	if (mmio->refcount == 0)
-		mmio_deregister(kvm, &mmio_tree, mmio);
+		mmio_deregister(kvm, tree, mmio);
 	else
 		mmio->remove = true;
 	mutex_unlock(&mmio_lock);
@@ -175,7 +185,8 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
 	return true;
 }
 
-bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
+		       u32 len, u8 is_write)
 {
 	struct mmio_mapping *mmio;
 
@@ -194,3 +205,31 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u
 out:
 	return true;
 }
+
+bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
+		     int direction, int size, u32 count)
+{
+	struct mmio_mapping *mmio;
+	bool is_write = direction == KVM_EXIT_IO_OUT;
+
+	mmio = mmio_get(&pio_tree, port, size);
+	if (!mmio) {
+		if (vcpu->kvm->cfg.ioport_debug) {
+			fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n",
+				to_direction(direction), port, size, count);
+
+			return false;
+		}
+		return true;
+	}
+
+	while (count--) {
+		mmio->mmio_fn(vcpu, port, data, size, is_write, mmio->ptr);
+
+		data += size;
+	}
+
+	mmio_put(vcpu->kvm, &pio_tree, mmio);
+
+	return true;
+}
-- 
2.17.1


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

* [PATCH kvmtool 05/21] hw/i8042: Clean up data types
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (3 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-11 16:55   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler Andre Przywara
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

The i8042 is clearly an 8-bit era device, so there is little room for
32-bit registers.
Clean up the data types used.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/i8042.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/hw/i8042.c b/hw/i8042.c
index 37a99a2d..36ee183f 100644
--- a/hw/i8042.c
+++ b/hw/i8042.c
@@ -64,11 +64,11 @@
 struct kbd_state {
 	struct kvm		*kvm;
 
-	char			kq[QUEUE_SIZE];	/* Keyboard queue */
+	u8			kq[QUEUE_SIZE];	/* Keyboard queue */
 	int			kread, kwrite;	/* Indexes into the queue */
 	int			kcount;		/* number of elements in queue */
 
-	char			mq[QUEUE_SIZE];
+	u8			mq[QUEUE_SIZE];
 	int			mread, mwrite;
 	int			mcount;
 
@@ -173,9 +173,9 @@ static void kbd_write_command(struct kvm *kvm, u8 val)
 /*
  * Called when the OS reads from port 0x60 (PS/2 data)
  */
-static u32 kbd_read_data(void)
+static u8 kbd_read_data(void)
 {
-	u32 ret;
+	u8 ret;
 	int i;
 
 	if (state.kcount != 0) {
@@ -202,9 +202,9 @@ static u32 kbd_read_data(void)
 /*
  * Called when the OS read from port 0x64, the command port
  */
-static u32 kbd_read_status(void)
+static u8 kbd_read_status(void)
 {
-	return (u32)state.status;
+	return state.status;
 }
 
 /*
@@ -212,7 +212,7 @@ static u32 kbd_read_status(void)
  * Things written here are generally arguments to commands previously
  * written to port 0x64 and stored in state.write_cmd
  */
-static void kbd_write_data(u32 val)
+static void kbd_write_data(u8 val)
 {
 	switch (state.write_cmd) {
 	case I8042_CMD_CTL_WCTR:
@@ -304,8 +304,8 @@ static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *
 		break;
 	}
 	case I8042_DATA_REG: {
-		u32 value = kbd_read_data();
-		ioport__write32(data, value);
+		u8 value = kbd_read_data();
+		ioport__write8(data, value);
 		break;
 	}
 	case I8042_PORT_B_REG: {
@@ -328,7 +328,7 @@ static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void
 		break;
 	}
 	case I8042_DATA_REG: {
-		u32 value = ioport__read32(data);
+		u8 value = ioport__read8(data);
 		kbd_write_data(value);
 		break;
 	}
-- 
2.17.1


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

* [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (4 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 05/21] hw/i8042: Clean up data types Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-11 17:23   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers Andre Przywara
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide an emulation function compatible with the MMIO
prototype.

Adjust the trap handler to use that new function, and provide shims to
implement the old ioport interface, for now.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
 1 file changed, 34 insertions(+), 34 deletions(-)

diff --git a/hw/i8042.c b/hw/i8042.c
index 36ee183f..eb1f9d28 100644
--- a/hw/i8042.c
+++ b/hw/i8042.c
@@ -292,52 +292,52 @@ static void kbd_reset(void)
 	};
 }
 
-/*
- * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
- */
-static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+		   u8 is_write, void *ptr)
 {
-	switch (port) {
-	case I8042_COMMAND_REG: {
-		u8 value = kbd_read_status();
-		ioport__write8(data, value);
+	u8 value;
+
+	if (is_write)
+		value = ioport__read8(data);
+
+	switch (addr) {
+	case I8042_COMMAND_REG:
+		if (is_write)
+			kbd_write_command(vcpu->kvm, value);
+		else
+			value = kbd_read_status();
 		break;
-	}
-	case I8042_DATA_REG: {
-		u8 value = kbd_read_data();
-		ioport__write8(data, value);
+	case I8042_DATA_REG:
+		if (is_write)
+			kbd_write_data(value);
+		else
+			value = kbd_read_data();
 		break;
-	}
-	case I8042_PORT_B_REG: {
-		ioport__write8(data, 0x20);
+	case I8042_PORT_B_REG:
+		if (!is_write)
+			value = 0x20;
 		break;
-	}
 	default:
-		return false;
+		return;
 	}
 
+	if (!is_write)
+		ioport__write8(data, value);
+}
+
+/*
+ * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
+ */
+static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+{
+	kbd_io(vcpu, port, data, size, false, NULL);
+
 	return true;
 }
 
 static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
-	switch (port) {
-	case I8042_COMMAND_REG: {
-		u8 value = ioport__read8(data);
-		kbd_write_command(vcpu->kvm, value);
-		break;
-	}
-	case I8042_DATA_REG: {
-		u8 value = ioport__read8(data);
-		kbd_write_data(value);
-		break;
-	}
-	case I8042_PORT_B_REG: {
-		break;
-	}
-	default:
-		return false;
-	}
+	kbd_io(vcpu, port, data, size, true, NULL);
 
 	return true;
 }
-- 
2.17.1


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

* [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (5 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 10:41   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 08/21] x86/ioport: Refactor " Andre Przywara
                   ` (14 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that the PC keyboard has a trap handler adhering to the MMIO fault
handler prototype, let's switch over to the joint registration routine.

This allows us to get rid of the ioport shim routines.

Make the kbd_init() function static on the way.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/i8042.c          | 30 ++++--------------------------
 include/kvm/i8042.h |  1 -
 2 files changed, 4 insertions(+), 27 deletions(-)

diff --git a/hw/i8042.c b/hw/i8042.c
index eb1f9d28..91d79dc4 100644
--- a/hw/i8042.c
+++ b/hw/i8042.c
@@ -325,40 +325,18 @@ static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 		ioport__write8(data, value);
 }
 
-/*
- * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
- */
-static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	kbd_io(vcpu, port, data, size, false, NULL);
-
-	return true;
-}
-
-static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	kbd_io(vcpu, port, data, size, true, NULL);
-
-	return true;
-}
-
-static struct ioport_operations kbd_ops = {
-	.io_in		= kbd_in,
-	.io_out		= kbd_out,
-};
-
-int kbd__init(struct kvm *kvm)
+static int kbd__init(struct kvm *kvm)
 {
 	int r;
 
 	kbd_reset();
 	state.kvm = kvm;
-	r = ioport__register(kvm, I8042_DATA_REG, &kbd_ops, 2, NULL);
+	r = kvm__register_pio(kvm, I8042_DATA_REG, 2, kbd_io, NULL);
 	if (r < 0)
 		return r;
-	r = ioport__register(kvm, I8042_COMMAND_REG, &kbd_ops, 2, NULL);
+	r = kvm__register_pio(kvm, I8042_COMMAND_REG, 2, kbd_io, NULL);
 	if (r < 0) {
-		ioport__unregister(kvm, I8042_DATA_REG);
+		kvm__deregister_pio(kvm, I8042_DATA_REG);
 		return r;
 	}
 
diff --git a/include/kvm/i8042.h b/include/kvm/i8042.h
index 3b4ab688..cd4ae6bb 100644
--- a/include/kvm/i8042.h
+++ b/include/kvm/i8042.h
@@ -7,6 +7,5 @@ struct kvm;
 
 void mouse_queue(u8 c);
 void kbd_queue(u8 c);
-int kbd__init(struct kvm *kvm);
 
 #endif
-- 
2.17.1


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

* [PATCH kvmtool 08/21] x86/ioport: Refactor trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (6 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 11:14   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 09/21] x86/ioport: Switch to new " Andre Przywara
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide emulation functions compatible with the MMIO
prototype.

Adjust the trap handlers to use that new function, and provide shims to
implement the old ioport interface, for now.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 x86/ioport.c | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/x86/ioport.c b/x86/ioport.c
index 8c5c7699..932da20a 100644
--- a/x86/ioport.c
+++ b/x86/ioport.c
@@ -3,8 +3,14 @@
 #include <stdlib.h>
 #include <stdio.h>
 
+static void dummy_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+		       u8 is_write, void *ptr)
+{
+}
+
 static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
+	dummy_mmio(vcpu, port, data, size, true, NULL);
 	return 0;
 }
 
@@ -12,15 +18,23 @@ static struct ioport_operations debug_ops = {
 	.io_out		= debug_io_out,
 };
 
-static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+			       u32 len, u8 is_write, void *ptr)
 {
 	char ch;
 
+	if (!is_write)
+		return;
+
 	ch = ioport__read8(data);
 
 	putchar(ch);
+}
 
-	return true;
+static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+{
+	seabios_debug_mmio(vcpu, port, data, size, true, NULL);
+	return 0;
 }
 
 static struct ioport_operations seabios_debug_ops = {
@@ -29,11 +43,13 @@ static struct ioport_operations seabios_debug_ops = {
 
 static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
+	dummy_mmio(vcpu, port, data, size, false, NULL);
 	return true;
 }
 
 static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
+	dummy_mmio(vcpu, port, data, size, true, NULL);
 	return true;
 }
 
@@ -50,13 +66,19 @@ static struct ioport_operations dummy_write_only_ioport_ops = {
  * The "fast A20 gate"
  */
 
-static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void ps2_control_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+			     u8 is_write, void *ptr)
 {
 	/*
 	 * A20 is always enabled.
 	 */
-	ioport__write8(data, 0x02);
+	if (!is_write)
+		ioport__write8(data, 0x02);
+}
 
+static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+{
+	ps2_control_mmio(vcpu, port, data, size, false, NULL);
 	return true;
 }
 
-- 
2.17.1


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

* [PATCH kvmtool 09/21] x86/ioport: Switch to new trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (7 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 08/21] x86/ioport: Refactor " Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 11:27   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 10/21] hw/rtc: Refactor " Andre Przywara
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that the x86 I/O ports have trap handlers adhering to the MMIO fault
handler prototype, let's switch over to the joint registration routine.

This allows us to get rid of the ioport shim routines.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 x86/ioport.c | 113 ++++++++++++++-------------------------------------
 1 file changed, 30 insertions(+), 83 deletions(-)

diff --git a/x86/ioport.c b/x86/ioport.c
index 932da20a..87955da1 100644
--- a/x86/ioport.c
+++ b/x86/ioport.c
@@ -8,16 +8,6 @@ static void dummy_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 {
 }
 
-static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	dummy_mmio(vcpu, port, data, size, true, NULL);
-	return 0;
-}
-
-static struct ioport_operations debug_ops = {
-	.io_out		= debug_io_out,
-};
-
 static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
 			       u32 len, u8 is_write, void *ptr)
 {
@@ -31,37 +21,6 @@ static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
 	putchar(ch);
 }
 
-static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	seabios_debug_mmio(vcpu, port, data, size, true, NULL);
-	return 0;
-}
-
-static struct ioport_operations seabios_debug_ops = {
-	.io_out		= seabios_debug_io_out,
-};
-
-static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	dummy_mmio(vcpu, port, data, size, false, NULL);
-	return true;
-}
-
-static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	dummy_mmio(vcpu, port, data, size, true, NULL);
-	return true;
-}
-
-static struct ioport_operations dummy_read_write_ioport_ops = {
-	.io_in		= dummy_io_in,
-	.io_out		= dummy_io_out,
-};
-
-static struct ioport_operations dummy_write_only_ioport_ops = {
-	.io_out		= dummy_io_out,
-};
-
 /*
  * The "fast A20 gate"
  */
@@ -76,17 +35,6 @@ static void ps2_control_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 		ioport__write8(data, 0x02);
 }
 
-static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	ps2_control_mmio(vcpu, port, data, size, false, NULL);
-	return true;
-}
-
-static struct ioport_operations ps2_control_a_ops = {
-	.io_in		= ps2_control_a_io_in,
-	.io_out		= dummy_io_out,
-};
-
 void ioport__map_irq(u8 *irq)
 {
 }
@@ -98,75 +46,75 @@ static int ioport__setup_arch(struct kvm *kvm)
 	/* Legacy ioport setup */
 
 	/* 0000 - 001F - DMA1 controller */
-	r = ioport__register(kvm, 0x0000, &dummy_read_write_ioport_ops, 32, NULL);
+	r = kvm__register_pio(kvm, 0x0000, 32, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 0x0020 - 0x003F - 8259A PIC 1 */
-	r = ioport__register(kvm, 0x0020, &dummy_read_write_ioport_ops, 2, NULL);
+	r = kvm__register_pio(kvm, 0x0020, 2, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
-	r = ioport__register(kvm, 0x0040, &dummy_read_write_ioport_ops, 4, NULL);
+	r = kvm__register_pio(kvm, 0x0040, 4, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 0092 - PS/2 system control port A */
-	r = ioport__register(kvm, 0x0092, &ps2_control_a_ops, 1, NULL);
+	r = kvm__register_pio(kvm, 0x0092, 1, ps2_control_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 0x00A0 - 0x00AF - 8259A PIC 2 */
-	r = ioport__register(kvm, 0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
+	r = kvm__register_pio(kvm, 0x00A0, 2, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 00C0 - 001F - DMA2 controller */
-	r = ioport__register(kvm, 0x00C0, &dummy_read_write_ioport_ops, 32, NULL);
+	r = kvm__register_pio(kvm, 0x00c0, 32, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 00E0-00EF are 'motherboard specific' so we use them for our
 	   internal debugging purposes.  */
-	r = ioport__register(kvm, IOPORT_DBG, &debug_ops, 1, NULL);
+	r = kvm__register_pio(kvm, IOPORT_DBG, 1, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 00ED - DUMMY PORT FOR DELAY??? */
-	r = ioport__register(kvm, 0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
+	r = kvm__register_pio(kvm, 0x00ed, 1, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 0x00F0 - 0x00FF - Math co-processor */
-	r = ioport__register(kvm, 0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
+	r = kvm__register_pio(kvm, 0x00f0, 2, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 0278-027A - PARALLEL PRINTER PORT (usually LPT1, sometimes LPT2) */
-	r = ioport__register(kvm, 0x0278, &dummy_read_write_ioport_ops, 3, NULL);
+	r = kvm__register_pio(kvm, 0x0278, 3, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 0378-037A - PARALLEL PRINTER PORT (usually LPT2, sometimes LPT3) */
-	r = ioport__register(kvm, 0x0378, &dummy_read_write_ioport_ops, 3, NULL);
+	r = kvm__register_pio(kvm, 0x0378, 3, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
-	r = ioport__register(kvm, 0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
+	r = kvm__register_pio(kvm, 0x03d4, 1, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
-	r = ioport__register(kvm, 0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
+	r = kvm__register_pio(kvm, 0x03d5, 1, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
-	r = ioport__register(kvm, 0x402, &seabios_debug_ops, 1, NULL);
+	r = kvm__register_pio(kvm, 0x0402, 1, seabios_debug_mmio, NULL);
 	if (r < 0)
 		return r;
 
 	/* 0510 - QEMU BIOS configuration register */
-	r = ioport__register(kvm, 0x510, &dummy_read_write_ioport_ops, 2, NULL);
+	r = kvm__register_pio(kvm, 0x0510, 2, dummy_mmio, NULL);
 	if (r < 0)
 		return r;
 
@@ -176,22 +124,21 @@ dev_base_init(ioport__setup_arch);
 
 static int ioport__remove_arch(struct kvm *kvm)
 {
-	ioport__unregister(kvm, 0x510);
-	ioport__unregister(kvm, 0x402);
-	ioport__unregister(kvm, 0x03D5);
-	ioport__unregister(kvm, 0x03D4);
-	ioport__unregister(kvm, 0x0378);
-	ioport__unregister(kvm, 0x0278);
-	ioport__unregister(kvm, 0x00F0);
-	ioport__unregister(kvm, 0x00ED);
-	ioport__unregister(kvm, IOPORT_DBG);
-	ioport__unregister(kvm, 0x00C0);
-	ioport__unregister(kvm, 0x00A0);
-	ioport__unregister(kvm, 0x0092);
-	ioport__unregister(kvm, 0x0040);
-	ioport__unregister(kvm, 0x0020);
-	ioport__unregister(kvm, 0x0000);
-
+	kvm__deregister_pio(kvm, 0x510);
+	kvm__deregister_pio(kvm, 0x402);
+	kvm__deregister_pio(kvm, 0x3d5);
+	kvm__deregister_pio(kvm, 0x3d4);
+	kvm__deregister_pio(kvm, 0x378);
+	kvm__deregister_pio(kvm, 0x278);
+	kvm__deregister_pio(kvm, 0x0f0);
+	kvm__deregister_pio(kvm, 0x0ed);
+	kvm__deregister_pio(kvm, IOPORT_DBG);
+	kvm__deregister_pio(kvm, 0x0c0);
+	kvm__deregister_pio(kvm, 0x0a0);
+	kvm__deregister_pio(kvm, 0x092);
+	kvm__deregister_pio(kvm, 0x040);
+	kvm__deregister_pio(kvm, 0x020);
+	kvm__deregister_pio(kvm, 0x000);
 	return 0;
 }
 dev_base_exit(ioport__remove_arch);
-- 
2.17.1


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

* [PATCH kvmtool 10/21] hw/rtc: Refactor trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (8 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 09/21] x86/ioport: Switch to new " Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 11:56   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler Andre Przywara
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide emulation functions compatible with the MMIO prototype.

Merge the two different trap handlers into one function, checking for
read/write and data/index register inside.
Adjust the trap handlers to use that new function, and provide shims to
implement the old ioport interface, for now.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/rtc.c | 70 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 35 insertions(+), 35 deletions(-)

diff --git a/hw/rtc.c b/hw/rtc.c
index 5483879f..664d4cb0 100644
--- a/hw/rtc.c
+++ b/hw/rtc.c
@@ -42,11 +42,37 @@ static inline unsigned char bin2bcd(unsigned val)
 	return ((val / 10) << 4) + val % 10;
 }
 
-static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+			u32 len, u8 is_write, void *ptr)
 {
 	struct tm *tm;
 	time_t ti;
 
+	if (is_write) {
+		if (addr == 0x70) {	/* index register */
+			u8 value = ioport__read8(data);
+
+			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
+			rtc.cmos_idx		= value & ~(1UL << 7);
+
+			return;
+		}
+
+		switch (rtc.cmos_idx) {
+		case RTC_REG_C:
+		case RTC_REG_D:
+			/* Read-only */
+			break;
+		default:
+			rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
+			break;
+		}
+		return;
+	}
+
+	if (addr == 0x70)
+		return;
+
 	time(&ti);
 
 	tm = gmtime(&ti);
@@ -92,42 +118,23 @@ static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 po
 		ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
 		break;
 	}
-
-	return true;
 }
 
-static bool cmos_ram_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static bool cmos_ram_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
-	switch (rtc.cmos_idx) {
-	case RTC_REG_C:
-	case RTC_REG_D:
-		/* Read-only */
-		break;
-	default:
-		rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
-		break;
-	}
-
+	cmos_ram_io(vcpu, port, data, size, false, NULL);
 	return true;
 }
 
-static struct ioport_operations cmos_ram_data_ioport_ops = {
-	.io_out		= cmos_ram_data_out,
-	.io_in		= cmos_ram_data_in,
-};
-
-static bool cmos_ram_index_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static bool cmos_ram_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
 {
-	u8 value = ioport__read8(data);
-
-	vcpu->kvm->nmi_disabled	= value & (1UL << 7);
-	rtc.cmos_idx		= value & ~(1UL << 7);
-
+	cmos_ram_io(vcpu, port, data, size, true, NULL);
 	return true;
 }
 
-static struct ioport_operations cmos_ram_index_ioport_ops = {
-	.io_out		= cmos_ram_index_out,
+static struct ioport_operations cmos_ram_ioport_ops = {
+	.io_out		= cmos_ram_out,
+	.io_in		= cmos_ram_in,
 };
 
 #ifdef CONFIG_HAS_LIBFDT
@@ -162,21 +169,15 @@ int rtc__init(struct kvm *kvm)
 		return r;
 
 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
-	r = ioport__register(kvm, 0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
+	r = ioport__register(kvm, 0x0070, &cmos_ram_ioport_ops, 2, NULL);
 	if (r < 0)
 		goto out_device;
 
-	r = ioport__register(kvm, 0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
-	if (r < 0)
-		goto out_ioport;
-
 	/* Set the VRT bit in Register D to indicate valid RAM and time */
 	rtc.cmos_data[RTC_REG_D] = RTC_REG_D_VRT;
 
 	return r;
 
-out_ioport:
-	ioport__unregister(kvm, 0x0070);
 out_device:
 	device__unregister(&rtc_dev_hdr);
 
@@ -188,7 +189,6 @@ int rtc__exit(struct kvm *kvm)
 {
 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
 	ioport__unregister(kvm, 0x0070);
-	ioport__unregister(kvm, 0x0071);
 
 	return 0;
 }
-- 
2.17.1


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

* [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (9 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 10/21] hw/rtc: Refactor " Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 12:02   ` Alexandru Elisei
  2020-12-10 14:28 ` [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler Andre Przywara
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that the RTC device has a trap handler adhering to the MMIO fault
handler prototype, let's switch over to the joint registration routine.

This allows us to get rid of the ioport shim routines.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/rtc.c | 21 ++-------------------
 1 file changed, 2 insertions(+), 19 deletions(-)

diff --git a/hw/rtc.c b/hw/rtc.c
index 664d4cb0..ee4c9102 100644
--- a/hw/rtc.c
+++ b/hw/rtc.c
@@ -120,23 +120,6 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
 	}
 }
 
-static bool cmos_ram_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	cmos_ram_io(vcpu, port, data, size, false, NULL);
-	return true;
-}
-
-static bool cmos_ram_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	cmos_ram_io(vcpu, port, data, size, true, NULL);
-	return true;
-}
-
-static struct ioport_operations cmos_ram_ioport_ops = {
-	.io_out		= cmos_ram_out,
-	.io_in		= cmos_ram_in,
-};
-
 #ifdef CONFIG_HAS_LIBFDT
 static void generate_rtc_fdt_node(void *fdt,
 				  struct device_header *dev_hdr,
@@ -169,7 +152,7 @@ int rtc__init(struct kvm *kvm)
 		return r;
 
 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
-	r = ioport__register(kvm, 0x0070, &cmos_ram_ioport_ops, 2, NULL);
+	r = kvm__register_pio(kvm, 0x0070, 2, cmos_ram_io, NULL);
 	if (r < 0)
 		goto out_device;
 
@@ -188,7 +171,7 @@ dev_init(rtc__init);
 int rtc__exit(struct kvm *kvm)
 {
 	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
-	ioport__unregister(kvm, 0x0070);
+	kvm__deregister_pio(kvm, 0x0070);
 
 	return 0;
 }
-- 
2.17.1


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

* [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (10 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler Andre Przywara
@ 2020-12-10 14:28 ` Andre Przywara
  2021-02-12 17:50   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 13/21] hw/serial: Refactor trap handler Andre Przywara
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:28 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

To be able to use the VESA device with the new generic I/O trap handler,
we need to use the different MMIO handler callback routine.

Replace the existing dummy in and out handlers with a joint dummy
MMIO handler, and register this using the new registration function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/vesa.c | 19 +++++--------------
 1 file changed, 5 insertions(+), 14 deletions(-)

diff --git a/hw/vesa.c b/hw/vesa.c
index 8659a002..7f82cdb4 100644
--- a/hw/vesa.c
+++ b/hw/vesa.c
@@ -43,21 +43,11 @@ static struct framebuffer vesafb = {
 	.mem_size	= VESA_MEM_SIZE,
 };
 
-static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void vesa_pci_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+		        u8 is_write, void *ptr)
 {
-	return true;
 }
 
-static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	return true;
-}
-
-static struct ioport_operations vesa_io_ops = {
-	.io_in			= vesa_pci_io_in,
-	.io_out			= vesa_pci_io_out,
-};
-
 static int vesa__bar_activate(struct kvm *kvm, struct pci_device_header *pci_hdr,
 			      int bar_num, void *data)
 {
@@ -82,7 +72,8 @@ struct framebuffer *vesa__init(struct kvm *kvm)
 	BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT);
 
 	vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE);
-	r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL);
+	r = kvm__register_pio(kvm, vesa_base_addr, PCI_IO_SIZE, vesa_pci_io,
+			      NULL);
 	if (r < 0)
 		goto out_error;
 
@@ -116,7 +107,7 @@ unmap_dev:
 unregister_device:
 	device__unregister(&vesa_device);
 unregister_ioport:
-	ioport__unregister(kvm, vesa_base_addr);
+	kvm__deregister_pio(kvm, vesa_base_addr);
 out_error:
 	return ERR_PTR(r);
 }
-- 
2.17.1


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

* [PATCH kvmtool 13/21] hw/serial: Refactor trap handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (11 preceding siblings ...)
  2020-12-10 14:28 ` [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-16 14:22   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers Andre Przywara
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide an emulation function compatible with the MMIO prototype.

Adjust the trap handler to use that new function, and provide shims to
implement the old ioport interface, for now.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/serial.c | 97 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 65 insertions(+), 32 deletions(-)

diff --git a/hw/serial.c b/hw/serial.c
index b0465d99..2907089c 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -242,36 +242,31 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
 	sysrq_pending = sysrq;
 }
 
-static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
-			   void *data, int size)
+static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
+			   u16 offset, u8 data)
 {
-	struct serial8250_device *dev = ioport->priv;
-	u16 offset;
 	bool ret = true;
-	char *addr = data;
 
 	mutex_lock(&dev->mutex);
 
-	offset = port - dev->iobase;
-
 	switch (offset) {
 	case UART_TX:
 		if (dev->lcr & UART_LCR_DLAB) {
-			dev->dll = ioport__read8(data);
+			dev->dll = data;
 			break;
 		}
 
 		/* Loopback mode */
 		if (dev->mcr & UART_MCR_LOOP) {
 			if (dev->rxcnt < FIFO_LEN) {
-				dev->rxbuf[dev->rxcnt++] = *addr;
+				dev->rxbuf[dev->rxcnt++] = data;
 				dev->lsr |= UART_LSR_DR;
 			}
 			break;
 		}
 
 		if (dev->txcnt < FIFO_LEN) {
-			dev->txbuf[dev->txcnt++] = *addr;
+			dev->txbuf[dev->txcnt++] = data;
 			dev->lsr &= ~UART_LSR_TEMT;
 			if (dev->txcnt == FIFO_LEN / 2)
 				dev->lsr &= ~UART_LSR_THRE;
@@ -283,18 +278,18 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
 		break;
 	case UART_IER:
 		if (!(dev->lcr & UART_LCR_DLAB))
-			dev->ier = ioport__read8(data) & 0x0f;
+			dev->ier = data & 0x0f;
 		else
-			dev->dlm = ioport__read8(data);
+			dev->dlm = data;
 		break;
 	case UART_FCR:
-		dev->fcr = ioport__read8(data);
+		dev->fcr = data;
 		break;
 	case UART_LCR:
-		dev->lcr = ioport__read8(data);
+		dev->lcr = data;
 		break;
 	case UART_MCR:
-		dev->mcr = ioport__read8(data);
+		dev->mcr = data;
 		break;
 	case UART_LSR:
 		/* Factory test */
@@ -303,7 +298,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
 		/* Not used */
 		break;
 	case UART_SCR:
-		dev->scr = ioport__read8(data);
+		dev->scr = data;
 		break;
 	default:
 		ret = false;
@@ -336,46 +331,43 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
 	}
 }
 
-static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
+			  u16 offset, u8 *data)
 {
-	struct serial8250_device *dev = ioport->priv;
-	u16 offset;
 	bool ret = true;
 
 	mutex_lock(&dev->mutex);
 
-	offset = port - dev->iobase;
-
 	switch (offset) {
 	case UART_RX:
 		if (dev->lcr & UART_LCR_DLAB)
-			ioport__write8(data, dev->dll);
+			*data = dev->dll;
 		else
 			serial8250_rx(dev, data);
 		break;
 	case UART_IER:
 		if (dev->lcr & UART_LCR_DLAB)
-			ioport__write8(data, dev->dlm);
+			*data = dev->dlm;
 		else
-			ioport__write8(data, dev->ier);
+			*data = dev->ier;
 		break;
 	case UART_IIR:
-		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
+		*data = dev->iir | UART_IIR_TYPE_BITS;
 		break;
 	case UART_LCR:
-		ioport__write8(data, dev->lcr);
+		*data = dev->lcr;
 		break;
 	case UART_MCR:
-		ioport__write8(data, dev->mcr);
+		*data = dev->mcr;
 		break;
 	case UART_LSR:
-		ioport__write8(data, dev->lsr);
+		*data = dev->lsr;
 		break;
 	case UART_MSR:
-		ioport__write8(data, dev->msr);
+		*data = dev->msr;
 		break;
 	case UART_SCR:
-		ioport__write8(data, dev->scr);
+		*data = dev->scr;
 		break;
 	default:
 		ret = false;
@@ -389,6 +381,47 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
 	return ret;
 }
 
+static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+			    u8 is_write, void *ptr)
+{
+	struct serial8250_device *dev = ptr;
+	u8 value = 0;
+
+	if (is_write) {
+		 value = *data;
+
+		serial8250_out(dev, vcpu, addr - dev->iobase, value);
+	} else {
+		if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
+			*data = value;
+	}
+}
+
+static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
+				  u16 port, void *data, int size)
+{
+	struct serial8250_device *dev = ioport->priv;
+	u8 value = ioport__read8(data);
+
+	serial8250_mmio(vcpu, port, &value, 1, true, dev);
+
+	return true;
+}
+
+static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
+				 u16 port, void *data, int size)
+{
+	struct serial8250_device *dev = ioport->priv;
+	u8 value = 0;
+
+
+	serial8250_mmio(vcpu, port, &value, 1, false, dev);
+
+	ioport__write8(data, value);
+
+	return true;
+}
+
 #ifdef CONFIG_HAS_LIBFDT
 
 char *fdt_stdout_path = NULL;
@@ -427,8 +460,8 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
 #endif
 
 static struct ioport_operations serial8250_ops = {
-	.io_in			= serial8250_in,
-	.io_out			= serial8250_out,
+	.io_in			= serial8250_ioport_in,
+	.io_out			= serial8250_ioport_out,
 };
 
 static int serial8250__device_init(struct kvm *kvm,
-- 
2.17.1


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

* [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (12 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 13/21] hw/serial: Refactor trap handler Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-16 14:31   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler Andre Przywara
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that the serial device has a trap handler adhering to the MMIO fault
handler prototype, let's switch over to the joint registration routine.

This allows us to get rid of the ioport shim routines.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/serial.c | 36 +++---------------------------------
 1 file changed, 3 insertions(+), 33 deletions(-)

diff --git a/hw/serial.c b/hw/serial.c
index 2907089c..d840eebc 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -397,31 +397,6 @@ static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 	}
 }
 
-static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
-				  u16 port, void *data, int size)
-{
-	struct serial8250_device *dev = ioport->priv;
-	u8 value = ioport__read8(data);
-
-	serial8250_mmio(vcpu, port, &value, 1, true, dev);
-
-	return true;
-}
-
-static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
-				 u16 port, void *data, int size)
-{
-	struct serial8250_device *dev = ioport->priv;
-	u8 value = 0;
-
-
-	serial8250_mmio(vcpu, port, &value, 1, false, dev);
-
-	ioport__write8(data, value);
-
-	return true;
-}
-
 #ifdef CONFIG_HAS_LIBFDT
 
 char *fdt_stdout_path = NULL;
@@ -459,11 +434,6 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
 }
 #endif
 
-static struct ioport_operations serial8250_ops = {
-	.io_in			= serial8250_ioport_in,
-	.io_out			= serial8250_ioport_out,
-};
-
 static int serial8250__device_init(struct kvm *kvm,
 				   struct serial8250_device *dev)
 {
@@ -474,7 +444,7 @@ static int serial8250__device_init(struct kvm *kvm,
 		return r;
 
 	ioport__map_irq(&dev->irq);
-	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);
+	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
 
 	return r;
 }
@@ -497,7 +467,7 @@ cleanup:
 	for (j = 0; j <= i; j++) {
 		struct serial8250_device *dev = &devices[j];
 
-		ioport__unregister(kvm, dev->iobase);
+		kvm__deregister_pio(kvm, dev->iobase);
 		device__unregister(&dev->dev_hdr);
 	}
 
@@ -513,7 +483,7 @@ int serial8250__exit(struct kvm *kvm)
 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
 		struct serial8250_device *dev = &devices[i];
 
-		r = ioport__unregister(kvm, dev->iobase);
+		r = kvm__deregister_pio(kvm, dev->iobase);
 		if (r < 0)
 			return r;
 		device__unregister(&dev->dev_hdr);
-- 
2.17.1


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

* [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (13 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-16 14:47   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers Andre Przywara
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide an emulation function compatible with the MMIO prototype.

Adjust the I/O port trap handler to use that new function, and provide
shims to implement the old ioport interface, for now.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 vfio/core.c | 51 ++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 36 insertions(+), 15 deletions(-)

diff --git a/vfio/core.c b/vfio/core.c
index 0b45e78b..f55f1f87 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -81,15 +81,12 @@ out_free_buf:
 	return ret;
 }
 
-static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
-			   u16 port, void *data, int len)
+static bool _vfio_ioport_in(struct vfio_region *region, u32 offset,
+			    void *data, int len)
 {
-	u32 val;
-	ssize_t nr;
-	struct vfio_region *region = ioport->priv;
 	struct vfio_device *vdev = region->vdev;
-
-	u32 offset = port - region->port_base;
+	ssize_t nr;
+	u32 val;
 
 	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_READ))
 		return false;
@@ -97,7 +94,7 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
 	nr = pread(vdev->fd, &val, len, region->info.offset + offset);
 	if (nr != len) {
 		vfio_dev_err(vdev, "could not read %d bytes from I/O port 0x%x\n",
-			     len, port);
+			     len, offset);
 		return false;
 	}
 
@@ -118,15 +115,13 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
 	return true;
 }
 
-static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
-			    u16 port, void *data, int len)
+static bool _vfio_ioport_out(struct vfio_region *region, u32 offset,
+			     void *data, int len)
 {
-	u32 val;
-	ssize_t nr;
-	struct vfio_region *region = ioport->priv;
 	struct vfio_device *vdev = region->vdev;
+	ssize_t nr;
+	u32 val;
 
-	u32 offset = port - region->port_base;
 
 	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_WRITE))
 		return false;
@@ -148,11 +143,37 @@ static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
 	nr = pwrite(vdev->fd, &val, len, region->info.offset + offset);
 	if (nr != len)
 		vfio_dev_err(vdev, "could not write %d bytes to I/O port 0x%x",
-			     len, port);
+			     len, offset);
 
 	return nr == len;
 }
 
+static void vfio_ioport_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
+			     u8 is_write, void *ptr)
+{
+	struct vfio_region *region = ptr;
+	u32 offset = addr - region->port_base;
+
+	if (is_write)
+		_vfio_ioport_out(region, offset, data, len);
+	else
+		_vfio_ioport_in(region, offset, data, len);
+}
+
+static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
+			    u16 port, void *data, int len)
+{
+	vfio_ioport_mmio(vcpu, port, data, len, true, ioport->priv);
+	return true;
+}
+
+static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
+			   u16 port, void *data, int len)
+{
+	vfio_ioport_mmio(vcpu, port, data, len, false, ioport->priv);
+	return true;
+}
+
 static struct ioport_operations vfio_ioport_ops = {
 	.io_in	= vfio_ioport_in,
 	.io_out	= vfio_ioport_out,
-- 
2.17.1


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

* [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (14 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-16 14:52   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler Andre Przywara
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that the vfio device has a trap handler adhering to the MMIO fault
handler prototype, let's switch over to the joint registration routine.

This allows us to get rid of the ioport shim routines.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 vfio/core.c | 29 ++++++-----------------------
 1 file changed, 6 insertions(+), 23 deletions(-)

diff --git a/vfio/core.c b/vfio/core.c
index f55f1f87..10919101 100644
--- a/vfio/core.c
+++ b/vfio/core.c
@@ -160,25 +160,6 @@ static void vfio_ioport_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 		_vfio_ioport_in(region, offset, data, len);
 }
 
-static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
-			    u16 port, void *data, int len)
-{
-	vfio_ioport_mmio(vcpu, port, data, len, true, ioport->priv);
-	return true;
-}
-
-static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
-			   u16 port, void *data, int len)
-{
-	vfio_ioport_mmio(vcpu, port, data, len, false, ioport->priv);
-	return true;
-}
-
-static struct ioport_operations vfio_ioport_ops = {
-	.io_in	= vfio_ioport_in,
-	.io_out	= vfio_ioport_out,
-};
-
 static void vfio_mmio_access(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
 			     u8 is_write, void *ptr)
 {
@@ -223,9 +204,11 @@ static int vfio_setup_trap_region(struct kvm *kvm, struct vfio_device *vdev,
 				  struct vfio_region *region)
 {
 	if (region->is_ioport) {
-		int port = ioport__register(kvm, region->port_base,
-					   &vfio_ioport_ops, region->info.size,
-					   region);
+		int port;
+
+		port = kvm__register_pio(kvm, region->port_base,
+					 region->info.size, vfio_ioport_mmio,
+					 region);
 		if (port < 0)
 			return port;
 		return 0;
@@ -292,7 +275,7 @@ void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region)
 		munmap(region->host_addr, region->info.size);
 		region->host_addr = NULL;
 	} else if (region->is_ioport) {
-		ioport__unregister(kvm, region->port_base);
+		kvm__deregister_pio(kvm, region->port_base);
 	} else {
 		kvm__deregister_mmio(kvm, region->guest_phys_addr);
 	}
-- 
2.17.1


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

* [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (15 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-16 17:03   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 18/21] pci: " Andre Przywara
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide an emulation function compatible with the MMIO prototype.

Adjust the existing MMIO callback routine to automatically determine
the region this trap came through, and call the existing I/O handlers.
Register the ioport region using the new registration function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 virtio/pci.c | 42 ++++++++++--------------------------------
 1 file changed, 10 insertions(+), 32 deletions(-)

diff --git a/virtio/pci.c b/virtio/pci.c
index 6eea6c68..49d3f4d5 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -178,15 +178,6 @@ static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev
 	return ret;
 }
 
-static bool virtio_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	struct virtio_device *vdev = ioport->priv;
-	struct virtio_pci *vpci = vdev->virtio;
-	unsigned long offset = port - virtio_pci__port_addr(vpci);
-
-	return virtio_pci__data_in(vcpu, vdev, offset, data, size);
-}
-
 static void update_msix_map(struct virtio_pci *vpci,
 			    struct msix_table *msix_entry, u32 vecnum)
 {
@@ -334,20 +325,6 @@ static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vde
 	return ret;
 }
 
-static bool virtio_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	struct virtio_device *vdev = ioport->priv;
-	struct virtio_pci *vpci = vdev->virtio;
-	unsigned long offset = port - virtio_pci__port_addr(vpci);
-
-	return virtio_pci__data_out(vcpu, vdev, offset, data, size);
-}
-
-static struct ioport_operations virtio_pci__io_ops = {
-	.io_in	= virtio_pci__io_in,
-	.io_out	= virtio_pci__io_out,
-};
-
 static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
 					   u64 addr, u8 *data, u32 len,
 					   u8 is_write, void *ptr)
@@ -455,12 +432,15 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
 {
 	struct virtio_device *vdev = ptr;
 	struct virtio_pci *vpci = vdev->virtio;
-	u32 mmio_addr = virtio_pci__mmio_addr(vpci);
+	u32 base_addr = virtio_pci__mmio_addr(vpci);
+
+	if (addr < base_addr || addr >= base_addr + PCI_IO_SIZE)
+		base_addr = virtio_pci__port_addr(vpci);
 
 	if (!is_write)
-		virtio_pci__data_in(vcpu, vdev, addr - mmio_addr, data, len);
+		virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
 	else
-		virtio_pci__data_out(vcpu, vdev, addr - mmio_addr, data, len);
+		virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len);
 }
 
 static int virtio_pci__bar_activate(struct kvm *kvm,
@@ -478,10 +458,8 @@ static int virtio_pci__bar_activate(struct kvm *kvm,
 
 	switch (bar_num) {
 	case 0:
-		r = ioport__register(kvm, bar_addr, &virtio_pci__io_ops,
-				     bar_size, vdev);
-		if (r > 0)
-			r = 0;
+		r = kvm__register_pio(kvm, bar_addr, bar_size,
+				      virtio_pci__io_mmio_callback, vdev);
 		break;
 	case 1:
 		r =  kvm__register_mmio(kvm, bar_addr, bar_size, false,
@@ -510,7 +488,7 @@ static int virtio_pci__bar_deactivate(struct kvm *kvm,
 
 	switch (bar_num) {
 	case 0:
-		r = ioport__unregister(kvm, bar_addr);
+		r = kvm__deregister_pio(kvm, bar_addr);
 		break;
 	case 1:
 	case 2:
@@ -625,7 +603,7 @@ int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
 	virtio_pci__reset(kvm, vdev);
 	kvm__deregister_mmio(kvm, virtio_pci__mmio_addr(vpci));
 	kvm__deregister_mmio(kvm, virtio_pci__msix_io_addr(vpci));
-	ioport__unregister(kvm, virtio_pci__port_addr(vpci));
+	kvm__deregister_pio(kvm, virtio_pci__port_addr(vpci));
 
 	return 0;
 }
-- 
2.17.1


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

* [PATCH kvmtool 18/21] pci: Switch trap handling to use MMIO handler
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (16 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-17 15:14   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 19/21] Remove ioport specific routines Andre Przywara
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

With the planned retirement of the special ioport emulation code, we
need to provide an emulation function compatible with the MMIO prototype.

Merge the existing _in and _out handlers to adhere to that MMIO
interface, and register these using the new registration function.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 pci.c | 82 +++++++++++++++++------------------------------------------
 1 file changed, 24 insertions(+), 58 deletions(-)

diff --git a/pci.c b/pci.c
index 2e2c0270..d6da79e0 100644
--- a/pci.c
+++ b/pci.c
@@ -87,29 +87,16 @@ static void *pci_config_address_ptr(u16 port)
 	return base + offset;
 }
 
-static bool pci_config_address_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void pci_config_address_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+				    u32 len, u8 is_write, void *ptr)
 {
-	void *p = pci_config_address_ptr(port);
+	void *p = pci_config_address_ptr(addr);
 
-	memcpy(p, data, size);
-
-	return true;
-}
-
-static bool pci_config_address_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	void *p = pci_config_address_ptr(port);
-
-	memcpy(data, p, size);
-
-	return true;
+	if (is_write)
+		memcpy(p, data, len);
+	else
+		memcpy(data, p, len);
 }
-
-static struct ioport_operations pci_config_address_ops = {
-	.io_in	= pci_config_address_in,
-	.io_out	= pci_config_address_out,
-};
-
 static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
 {
 	union pci_config_address pci_config_address;
@@ -125,49 +112,27 @@ static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_numbe
 	return !IS_ERR_OR_NULL(device__find_dev(DEVICE_BUS_PCI, device_number));
 }
 
-static bool pci_config_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
-{
-	union pci_config_address pci_config_address;
-
-	if (size > 4)
-		size = 4;
-
-	pci_config_address.w = ioport__read32(&pci_config_address_bits);
-	/*
-	 * If someone accesses PCI configuration space offsets that are not
-	 * aligned to 4 bytes, it uses ioports to signify that.
-	 */
-	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
-
-	pci__config_wr(vcpu->kvm, pci_config_address, data, size);
-
-	return true;
-}
-
-static bool pci_config_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
+static void pci_config_data_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
+				 u32 len, u8 is_write, void *kvm)
 {
 	union pci_config_address pci_config_address;
 
-	if (size > 4)
-		size = 4;
+	if (len > 4)
+		len = 4;
 
 	pci_config_address.w = ioport__read32(&pci_config_address_bits);
 	/*
 	 * If someone accesses PCI configuration space offsets that are not
 	 * aligned to 4 bytes, it uses ioports to signify that.
 	 */
-	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
+	pci_config_address.reg_offset = addr - PCI_CONFIG_DATA;
 
-	pci__config_rd(vcpu->kvm, pci_config_address, data, size);
-
-	return true;
+	if (is_write)
+		pci__config_wr(vcpu->kvm, pci_config_address, data, len);
+	else
+		pci__config_rd(vcpu->kvm, pci_config_address, data, len);
 }
 
-static struct ioport_operations pci_config_data_ops = {
-	.io_in	= pci_config_data_in,
-	.io_out	= pci_config_data_out,
-};
-
 static int pci_activate_bar(struct kvm *kvm, struct pci_device_header *pci_hdr,
 			    int bar_num)
 {
@@ -512,11 +477,12 @@ int pci__init(struct kvm *kvm)
 {
 	int r;
 
-	r = ioport__register(kvm, PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
+	r = kvm__register_pio(kvm, PCI_CONFIG_DATA, 4,
+				 pci_config_data_mmio, NULL);
 	if (r < 0)
 		return r;
-
-	r = ioport__register(kvm, PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
+	r = kvm__register_pio(kvm, PCI_CONFIG_ADDRESS, 4,
+				 pci_config_address_mmio, NULL);
 	if (r < 0)
 		goto err_unregister_data;
 
@@ -528,17 +494,17 @@ int pci__init(struct kvm *kvm)
 	return 0;
 
 err_unregister_addr:
-	ioport__unregister(kvm, PCI_CONFIG_ADDRESS);
+	kvm__deregister_pio(kvm, PCI_CONFIG_ADDRESS);
 err_unregister_data:
-	ioport__unregister(kvm, PCI_CONFIG_DATA);
+	kvm__deregister_pio(kvm, PCI_CONFIG_DATA);
 	return r;
 }
 dev_base_init(pci__init);
 
 int pci__exit(struct kvm *kvm)
 {
-	ioport__unregister(kvm, PCI_CONFIG_DATA);
-	ioport__unregister(kvm, PCI_CONFIG_ADDRESS);
+	kvm__deregister_pio(kvm, PCI_CONFIG_DATA);
+	kvm__deregister_pio(kvm, PCI_CONFIG_ADDRESS);
 
 	return 0;
 }
-- 
2.17.1


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

* [PATCH kvmtool 19/21] Remove ioport specific routines
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (17 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 18/21] pci: " Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-17 15:49   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses Andre Przywara
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Now that all users of the dedicated ioport trap handler interface are
gone, we can retire the code associated with it.

This removes ioport.c and ioport.h, along with removing prototypes from
other header files.

This also transfers the responsibility for port I/O trap handling
entirely into the new routine in mmio.c.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 Makefile             |   1 -
 include/kvm/ioport.h |  20 -----
 include/kvm/kvm.h    |   2 -
 ioport.c             | 173 -------------------------------------------
 mmio.c               |   2 +-
 5 files changed, 1 insertion(+), 197 deletions(-)
 delete mode 100644 ioport.c

diff --git a/Makefile b/Makefile
index 35bb1182..94ff5da6 100644
--- a/Makefile
+++ b/Makefile
@@ -56,7 +56,6 @@ OBJS	+= framebuffer.o
 OBJS	+= guest_compat.o
 OBJS	+= hw/rtc.o
 OBJS	+= hw/serial.o
-OBJS	+= ioport.o
 OBJS	+= irq.o
 OBJS	+= kvm-cpu.o
 OBJS	+= kvm.o
diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
index a61038e2..38636553 100644
--- a/include/kvm/ioport.h
+++ b/include/kvm/ioport.h
@@ -17,28 +17,8 @@
 
 struct kvm;
 
-struct ioport {
-	struct rb_int_node		node;
-	struct ioport_operations	*ops;
-	void				*priv;
-	struct device_header		dev_hdr;
-	u32				refcount;
-	bool				remove;
-};
-
-struct ioport_operations {
-	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
-	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
-};
-
 void ioport__map_irq(u8 *irq);
 
-int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
-				  int count, void *param);
-int ioport__unregister(struct kvm *kvm, u16 port);
-int ioport__init(struct kvm *kvm);
-int ioport__exit(struct kvm *kvm);
-
 static inline u8 ioport__read8(u8 *data)
 {
 	return *data;
diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
index 14f9d58b..e70f8ef6 100644
--- a/include/kvm/kvm.h
+++ b/include/kvm/kvm.h
@@ -119,8 +119,6 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
 void kvm__irq_trigger(struct kvm *kvm, int irq);
 bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
 bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
-bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
-		      int direction, int size, u32 count);
 int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
 int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
 		      enum kvm_mem_type type);
diff --git a/ioport.c b/ioport.c
deleted file mode 100644
index 204d8103..00000000
--- a/ioport.c
+++ /dev/null
@@ -1,173 +0,0 @@
-#include "kvm/ioport.h"
-
-#include "kvm/kvm.h"
-#include "kvm/util.h"
-#include "kvm/rbtree-interval.h"
-#include "kvm/mutex.h"
-
-#include <linux/kvm.h>	/* for KVM_EXIT_* */
-#include <linux/types.h>
-
-#include <stdbool.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#define ioport_node(n) rb_entry(n, struct ioport, node)
-
-static DEFINE_MUTEX(ioport_lock);
-
-static struct rb_root		ioport_tree = RB_ROOT;
-
-static struct ioport *ioport_search(struct rb_root *root, u64 addr)
-{
-	struct rb_int_node *node;
-
-	node = rb_int_search_single(root, addr);
-	if (node == NULL)
-		return NULL;
-
-	return ioport_node(node);
-}
-
-static int ioport_insert(struct rb_root *root, struct ioport *data)
-{
-	return rb_int_insert(root, &data->node);
-}
-
-static void ioport_remove(struct rb_root *root, struct ioport *data)
-{
-	rb_int_erase(root, &data->node);
-}
-
-static struct ioport *ioport_get(struct rb_root *root, u64 addr)
-{
-	struct ioport *ioport;
-
-	mutex_lock(&ioport_lock);
-	ioport = ioport_search(root, addr);
-	if (ioport)
-		ioport->refcount++;
-	mutex_unlock(&ioport_lock);
-
-	return ioport;
-}
-
-/* Called with ioport_lock held. */
-static void ioport_unregister(struct rb_root *root, struct ioport *data)
-{
-	ioport_remove(root, data);
-	free(data);
-}
-
-static void ioport_put(struct rb_root *root, struct ioport *data)
-{
-	mutex_lock(&ioport_lock);
-	data->refcount--;
-	if (data->remove && data->refcount == 0)
-		ioport_unregister(root, data);
-	mutex_unlock(&ioport_lock);
-}
-
-int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
-{
-	struct ioport *entry;
-	int r;
-
-	entry = malloc(sizeof(*entry));
-	if (entry == NULL)
-		return -ENOMEM;
-
-	*entry = (struct ioport) {
-		.node		= RB_INT_INIT(port, port + count),
-		.ops		= ops,
-		.priv		= param,
-		/*
-		 * Start from 0 because ioport__unregister() doesn't decrement
-		 * the reference count.
-		 */
-		.refcount	= 0,
-		.remove		= false,
-	};
-
-	mutex_lock(&ioport_lock);
-	r = ioport_insert(&ioport_tree, entry);
-	if (r < 0)
-		goto out_free;
-	mutex_unlock(&ioport_lock);
-
-	return port;
-
-out_free:
-	free(entry);
-	mutex_unlock(&ioport_lock);
-	return r;
-}
-
-int ioport__unregister(struct kvm *kvm, u16 port)
-{
-	struct ioport *entry;
-
-	mutex_lock(&ioport_lock);
-	entry = ioport_search(&ioport_tree, port);
-	if (!entry) {
-		mutex_unlock(&ioport_lock);
-		return -ENOENT;
-	}
-	/* The same reasoning from kvm__deregister_mmio() applies. */
-	if (entry->refcount == 0)
-		ioport_unregister(&ioport_tree, entry);
-	else
-		entry->remove = true;
-	mutex_unlock(&ioport_lock);
-
-	return 0;
-}
-
-static const char *to_direction(int direction)
-{
-	if (direction == KVM_EXIT_IO_IN)
-		return "IN";
-	else
-		return "OUT";
-}
-
-static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
-{
-	fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
-}
-
-bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
-{
-	struct ioport_operations *ops;
-	bool ret = false;
-	struct ioport *entry;
-	void *ptr = data;
-	struct kvm *kvm = vcpu->kvm;
-
-	entry = ioport_get(&ioport_tree, port);
-	if (!entry)
-		return kvm__emulate_pio(vcpu, port, data, direction,
-					size, count);
-
-	ops	= entry->ops;
-
-	while (count--) {
-		if (direction == KVM_EXIT_IO_IN && ops->io_in)
-				ret = ops->io_in(entry, vcpu, port, ptr, size);
-		else if (direction == KVM_EXIT_IO_OUT && ops->io_out)
-				ret = ops->io_out(entry, vcpu, port, ptr, size);
-
-		ptr += size;
-	}
-
-	ioport_put(&ioport_tree, entry);
-
-	if (ret)
-		return true;
-
-	if (kvm->cfg.ioport_debug)
-		ioport_error(port, data, direction, size, count);
-
-	return !kvm->cfg.ioport_debug;
-}
diff --git a/mmio.c b/mmio.c
index 4cce1901..5249af39 100644
--- a/mmio.c
+++ b/mmio.c
@@ -206,7 +206,7 @@ out:
 	return true;
 }
 
-bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
+bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data,
 		     int direction, int size, u32 count)
 {
 	struct mmio_mapping *mmio;
-- 
2.17.1


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

* [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (18 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 19/21] Remove ioport specific routines Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-17 16:48   ` Alexandru Elisei
  2020-12-10 14:29 ` [PATCH kvmtool 21/21] hw/rtc: " Andre Przywara
  2021-02-10 17:44 ` [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Alexandru Elisei
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Using the UART devices at their legacy I/O addresses as set by IBM in
1981 was a kludge we used for simplicity on ARM platforms as well.
However this imposes problems due to their missing alignment and overlap
with the PCI I/O address space.

Now that we can switch a device easily between using ioports and MMIO,
let's move the UARTs out of the first 4K of memory on ARM platforms.

That should be transparent for well behaved guests, since the change is
naturally reflected in the device tree. Even "earlycon" keeps working,
as the stdout-path property is adjusted automatically.

People providing direct earlycon parameters via the command line need to
adjust it to: "earlycon=uart,mmio,0x1000000".

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/serial.c | 52 ++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 36 insertions(+), 16 deletions(-)

diff --git a/hw/serial.c b/hw/serial.c
index d840eebc..00fb3aa8 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -13,6 +13,24 @@
 
 #include <pthread.h>
 
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+#define serial_iobase(nr)	(0x1000000 + (nr) * 0x1000)
+#define serial_irq(nr)		(32 + (nr))
+#define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
+#else
+#define serial_iobase_0		0x3f8
+#define serial_iobase_1		0x2f8
+#define serial_iobase_2		0x3e8
+#define serial_iobase_3		0x2e8
+#define serial_irq_0		4
+#define serial_irq_1		3
+#define serial_irq_2		4
+#define serial_irq_3		3
+#define serial_iobase(nr)	serial_iobase_##nr
+#define serial_irq(nr)		serial_irq_##nr
+#define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
+#endif
+
 /*
  * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
  * expects that for autodetection.
@@ -27,7 +45,7 @@ struct serial8250_device {
 	struct mutex		mutex;
 	u8			id;
 
-	u16			iobase;
+	u32			iobase;
 	u8			irq;
 	u8			irq_state;
 	int			txcnt;
@@ -65,56 +83,56 @@ static struct serial8250_device devices[] = {
 	/* ttyS0 */
 	[0]	= {
 		.dev_hdr = {
-			.bus_type	= DEVICE_BUS_IOPORT,
+			.bus_type	= SERIAL8250_BUS_TYPE,
 			.data		= serial8250_generate_fdt_node,
 		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 0,
-		.iobase			= 0x3f8,
-		.irq			= 4,
+		.iobase			= serial_iobase(0),
+		.irq			= serial_irq(0),
 
 		SERIAL_REGS_SETTING
 	},
 	/* ttyS1 */
 	[1]	= {
 		.dev_hdr = {
-			.bus_type	= DEVICE_BUS_IOPORT,
+			.bus_type	= SERIAL8250_BUS_TYPE,
 			.data		= serial8250_generate_fdt_node,
 		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 1,
-		.iobase			= 0x2f8,
-		.irq			= 3,
+		.iobase			= serial_iobase(1),
+		.irq			= serial_irq(1),
 
 		SERIAL_REGS_SETTING
 	},
 	/* ttyS2 */
 	[2]	= {
 		.dev_hdr = {
-			.bus_type	= DEVICE_BUS_IOPORT,
+			.bus_type	= SERIAL8250_BUS_TYPE,
 			.data		= serial8250_generate_fdt_node,
 		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 2,
-		.iobase			= 0x3e8,
-		.irq			= 4,
+		.iobase			= serial_iobase(2),
+		.irq			= serial_irq(2),
 
 		SERIAL_REGS_SETTING
 	},
 	/* ttyS3 */
 	[3]	= {
 		.dev_hdr = {
-			.bus_type	= DEVICE_BUS_IOPORT,
+			.bus_type	= SERIAL8250_BUS_TYPE,
 			.data		= serial8250_generate_fdt_node,
 		},
 		.mutex			= MUTEX_INITIALIZER,
 
 		.id			= 3,
-		.iobase			= 0x2e8,
-		.irq			= 3,
+		.iobase			= serial_iobase(3),
+		.irq			= serial_irq(3),
 
 		SERIAL_REGS_SETTING
 	},
@@ -444,7 +462,8 @@ static int serial8250__device_init(struct kvm *kvm,
 		return r;
 
 	ioport__map_irq(&dev->irq);
-	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
+	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
+				 SERIAL8250_BUS_TYPE);
 
 	return r;
 }
@@ -467,7 +486,7 @@ cleanup:
 	for (j = 0; j <= i; j++) {
 		struct serial8250_device *dev = &devices[j];
 
-		kvm__deregister_pio(kvm, dev->iobase);
+		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
 		device__unregister(&dev->dev_hdr);
 	}
 
@@ -483,7 +502,8 @@ int serial8250__exit(struct kvm *kvm)
 	for (i = 0; i < ARRAY_SIZE(devices); i++) {
 		struct serial8250_device *dev = &devices[i];
 
-		r = kvm__deregister_pio(kvm, dev->iobase);
+		r = kvm__deregister_iotrap(kvm, dev->iobase,
+					   SERIAL8250_BUS_TYPE);
 		if (r < 0)
 			return r;
 		device__unregister(&dev->dev_hdr);
-- 
2.17.1


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

* [PATCH kvmtool 21/21] hw/rtc: ARM/arm64: Use MMIO at higher addresses
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (19 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses Andre Przywara
@ 2020-12-10 14:29 ` Andre Przywara
  2021-02-18 13:33   ` Alexandru Elisei
  2021-02-10 17:44 ` [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Alexandru Elisei
  21 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2020-12-10 14:29 UTC (permalink / raw)
  To: Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Alexandru Elisei, Marc Zyngier

Using the RTC device at its legacy I/O address as set by IBM in 1981
was a kludge we used for simplicity on ARM platforms as well.
However this imposes problems due to their missing alignment and overlap
with the PCI I/O address space.

Now that we can switch a device easily between using ioports and
MMIO, let's move the RTC out of the first 4K of memory on ARM platforms.

That should be transparent for well behaved guests, since the change is
naturally reflected in the device tree.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 hw/rtc.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/hw/rtc.c b/hw/rtc.c
index ee4c9102..bdb88f0f 100644
--- a/hw/rtc.c
+++ b/hw/rtc.c
@@ -5,6 +5,15 @@
 
 #include <time.h>
 
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
+#define RTC_BUS_TYPE		DEVICE_BUS_MMIO
+#define RTC_BASE_ADDRESS	0x1010000
+#else
+/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
+#define RTC_BUS_TYPE		DEVICE_BUS_IOPORT
+#define RTC_BASE_ADDRESS	0x70
+#endif
+
 /*
  * MC146818 RTC registers
  */
@@ -49,7 +58,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
 	time_t ti;
 
 	if (is_write) {
-		if (addr == 0x70) {	/* index register */
+		if (addr == RTC_BASE_ADDRESS) {	/* index register */
 			u8 value = ioport__read8(data);
 
 			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
@@ -70,7 +79,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
 		return;
 	}
 
-	if (addr == 0x70)
+	if (addr == RTC_BASE_ADDRESS)	/* index register is write-only */
 		return;
 
 	time(&ti);
@@ -127,7 +136,7 @@ static void generate_rtc_fdt_node(void *fdt,
 							    u8 irq,
 							    enum irq_type))
 {
-	u64 reg_prop[2] = { cpu_to_fdt64(0x70), cpu_to_fdt64(2) };
+	u64 reg_prop[2] = { cpu_to_fdt64(RTC_BASE_ADDRESS), cpu_to_fdt64(2) };
 
 	_FDT(fdt_begin_node(fdt, "rtc"));
 	_FDT(fdt_property_string(fdt, "compatible", "motorola,mc146818"));
@@ -139,7 +148,7 @@ static void generate_rtc_fdt_node(void *fdt,
 #endif
 
 struct device_header rtc_dev_hdr = {
-	.bus_type = DEVICE_BUS_IOPORT,
+	.bus_type = RTC_BUS_TYPE,
 	.data = generate_rtc_fdt_node,
 };
 
@@ -151,8 +160,8 @@ int rtc__init(struct kvm *kvm)
 	if (r < 0)
 		return r;
 
-	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
-	r = kvm__register_pio(kvm, 0x0070, 2, cmos_ram_io, NULL);
+	r = kvm__register_iotrap(kvm, RTC_BASE_ADDRESS, 2, cmos_ram_io, NULL,
+				 RTC_BUS_TYPE);
 	if (r < 0)
 		goto out_device;
 
@@ -170,8 +179,7 @@ dev_init(rtc__init);
 
 int rtc__exit(struct kvm *kvm)
 {
-	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
-	kvm__deregister_pio(kvm, 0x0070);
+	kvm__deregister_iotrap(kvm, RTC_BASE_ADDRESS, RTC_BUS_TYPE);
 
 	return 0;
 }
-- 
2.17.1


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

* Re: [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling
  2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
                   ` (20 preceding siblings ...)
  2020-12-10 14:29 ` [PATCH kvmtool 21/21] hw/rtc: " Andre Przywara
@ 2021-02-10 17:44 ` Alexandru Elisei
  21 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-10 17:44 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> At the moment we use two separate code paths to handle exits for
> KVM_EXIT_IO (ioport.c) and KVM_EXIT_MMIO (mmio.c), even though they
> are semantically very similar. Because the trap handler callback routine
> is different, devices need to decide on one conduit or need to provide
> different handler functions for both of them.
>
> This is not only unnecessary code duplication, but makes switching
> devices from I/O port to MMIO a tedious task, even though there is no
> real difference between the two, especially on ARM and PowerPC.
>
> For ARM we aim at providing a flexible memory layout, and also have
> trouble with the UART and RTC device overlapping with the PCI I/O area,
> so it seems indicated to tackle this once and for all.
>
> The first three patches do some cleanup, to simplify things later.
>
> Patch 04/21 lays the groundwork, by extending mmio.c to be able to also
> register I/O port trap handlers, using the same callback prototype as
> we use for MMIO.
>
> The next 14 patches then convert devices that use the I/O port
> interface over to the new joint interface. This requires to rework
> the trap handler routine to adhere to the same prototype as the existing
> MMIO handlers. For most devices this is done in two steps: a first to
> introduce the reworked handler routine, and a second to switch to the new
> joint registration routine. For some devices the first step is trivial,
> so it's done in one patch.
>
> Patch 19/21 then retires the old I/O port interface, by removing ioport.c
> and friends.
>
> The final two patches switch the UART and the RTC device over to register
> on the MMIO "bus", when running on ARM or arm64. This changes the
> addresses to be at 16MB, so they are not in the PCI I/O area anymore.
>
> Admittedly this goal can be achieved much simpler, by just having the
> first three patches, and some more changes and ifdef's in the last two,
> but I figured it would be good to clean up the I/O port mess for good.

This is a very good idea, I thought more than once as I was working on other
things that there really is no reason to differentiate between ioport and mmio
emulation.

Thanks,

Alex

>
> Please have a look and comment!
>
> Cheers,
> Andre
>
> Andre Przywara (21):
>   ioport: Remove ioport__setup_arch()
>   hw/serial: Use device abstraction for FDT generator function
>   ioport: Retire .generate_fdt_node functionality
>   mmio: Extend handling to include ioport emulation
>   hw/i8042: Clean up data types
>   hw/i8042: Refactor trap handler
>   hw/i8042: Switch to new trap handlers
>   x86/ioport: Refactor trap handlers
>   x86/ioport: Switch to new trap handlers
>   hw/rtc: Refactor trap handlers
>   hw/rtc: Switch to new trap handler
>   hw/vesa: Switch trap handling to use MMIO handler
>   hw/serial: Refactor trap handler
>   hw/serial: Switch to new trap handlers
>   vfio: Refactor ioport trap handler
>   vfio: Switch to new ioport trap handlers
>   virtio: Switch trap handling to use MMIO handler
>   pci: Switch trap handling to use MMIO handler
>   Remove ioport specific routines
>   hw/serial: ARM/arm64: Use MMIO at higher addresses
>   hw/rtc: ARM/arm64: Use MMIO at higher addresses
>
>  Makefile             |   1 -
>  arm/ioport.c         |   5 -
>  hw/i8042.c           |  88 ++++++----------
>  hw/rtc.c             |  91 ++++++++---------
>  hw/serial.c          | 166 +++++++++++++++++++-----------
>  hw/vesa.c            |  19 +---
>  include/kvm/i8042.h  |   1 -
>  include/kvm/ioport.h |  25 -----
>  include/kvm/kvm.h    |  42 +++++++-
>  ioport.c             | 235 -------------------------------------------
>  mips/kvm.c           |   5 -
>  mmio.c               |  59 +++++++++--
>  pci.c                |  82 +++++----------
>  powerpc/ioport.c     |   6 --
>  vfio/core.c          |  50 ++++-----
>  virtio/pci.c         |  42 ++------
>  x86/ioport.c         | 106 +++++++++----------
>  17 files changed, 385 insertions(+), 638 deletions(-)
>  delete mode 100644 ioport.c
>

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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2020-12-10 14:28 ` [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch() Andre Przywara
@ 2021-02-10 17:44   ` Alexandru Elisei
  2021-02-11 17:16     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-10 17:44 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> Since x86 had a special need for registering tons of special I/O ports,
> we had an ioport__setup_arch() callback, to allow each architecture
> to do the same. As it turns out no one uses it beside x86, so we remove
> that unnecessary abstraction.
>
> The generic function was registered via a device_base_init() call, so
> we just do the same for the x86 specific function only, and can remove
> the unneeded ioport__setup_arch().
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  arm/ioport.c         |  5 -----
>  include/kvm/ioport.h |  1 -
>  ioport.c             | 28 ----------------------------
>  mips/kvm.c           |  5 -----
>  powerpc/ioport.c     |  6 ------
>  x86/ioport.c         | 25 ++++++++++++++++++++++++-
>  6 files changed, 24 insertions(+), 46 deletions(-)
>
> diff --git a/arm/ioport.c b/arm/ioport.c
> index 2f0feb9a..24092c9d 100644
> --- a/arm/ioport.c
> +++ b/arm/ioport.c
> @@ -1,11 +1,6 @@
>  #include "kvm/ioport.h"
>  #include "kvm/irq.h"
>  
> -int ioport__setup_arch(struct kvm *kvm)
> -{
> -	return 0;
> -}
> -
>  void ioport__map_irq(u8 *irq)
>  {
>  	*irq = irq__alloc_line();
> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> index 039633f7..d0213541 100644
> --- a/include/kvm/ioport.h
> +++ b/include/kvm/ioport.h
> @@ -35,7 +35,6 @@ struct ioport_operations {
>  							    enum irq_type));
>  };
>  
> -int ioport__setup_arch(struct kvm *kvm);
>  void ioport__map_irq(u8 *irq);
>  
>  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> diff --git a/ioport.c b/ioport.c
> index 844a832d..667e8386 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
>  	return 0;
>  }
>  
> -static void ioport__unregister_all(void)
> -{
> -	struct ioport *entry;
> -	struct rb_node *rb;
> -	struct rb_int_node *rb_node;
> -
> -	rb = rb_first(&ioport_tree);
> -	while (rb) {
> -		rb_node = rb_int(rb);
> -		entry = ioport_node(rb_node);
> -		ioport_unregister(&ioport_tree, entry);
> -		rb = rb_first(&ioport_tree);
> -	}
> -}

I get the impression this is a rebasing artifact. The commit message doesn't
mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
far as I can tell it's still needed because there are places other than
ioport__setup_arch() from where ioport__register() is called.

Thanks,

Alex

> -
>  static const char *to_direction(int direction)
>  {
>  	if (direction == KVM_EXIT_IO_IN)
> @@ -220,16 +205,3 @@ out:
>  
>  	return !kvm->cfg.ioport_debug;
>  }
> -
> -int ioport__init(struct kvm *kvm)
> -{
> -	return ioport__setup_arch(kvm);
> -}
> -dev_base_init(ioport__init);
> -
> -int ioport__exit(struct kvm *kvm)
> -{
> -	ioport__unregister_all();
> -	return 0;
> -}
> -dev_base_exit(ioport__exit);
> diff --git a/mips/kvm.c b/mips/kvm.c
> index 26355930..e110e5d5 100644
> --- a/mips/kvm.c
> +++ b/mips/kvm.c
> @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
>  		die_perror("KVM_IRQ_LINE ioctl");
>  }
>  
> -int ioport__setup_arch(struct kvm *kvm)
> -{
> -	return 0;
> -}
> -
>  bool kvm__arch_cpu_supports_vm(void)
>  {
>  	return true;
> diff --git a/powerpc/ioport.c b/powerpc/ioport.c
> index 0c188b61..a5cff4ee 100644
> --- a/powerpc/ioport.c
> +++ b/powerpc/ioport.c
> @@ -12,12 +12,6 @@
>  
>  #include <stdlib.h>
>  
> -int ioport__setup_arch(struct kvm *kvm)
> -{
> -	/* PPC has no legacy ioports to set up */
> -	return 0;
> -}
> -
>  void ioport__map_irq(u8 *irq)
>  {
>  }
> diff --git a/x86/ioport.c b/x86/ioport.c
> index 7ad7b8f3..8c5c7699 100644
> --- a/x86/ioport.c
> +++ b/x86/ioport.c
> @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
>  {
>  }
>  
> -int ioport__setup_arch(struct kvm *kvm)
> +static int ioport__setup_arch(struct kvm *kvm)
>  {
>  	int r;
>  
> @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
>  
>  	return 0;
>  }
> +dev_base_init(ioport__setup_arch);
> +
> +static int ioport__remove_arch(struct kvm *kvm)
> +{
> +	ioport__unregister(kvm, 0x510);
> +	ioport__unregister(kvm, 0x402);
> +	ioport__unregister(kvm, 0x03D5);
> +	ioport__unregister(kvm, 0x03D4);
> +	ioport__unregister(kvm, 0x0378);
> +	ioport__unregister(kvm, 0x0278);
> +	ioport__unregister(kvm, 0x00F0);
> +	ioport__unregister(kvm, 0x00ED);
> +	ioport__unregister(kvm, IOPORT_DBG);
> +	ioport__unregister(kvm, 0x00C0);
> +	ioport__unregister(kvm, 0x00A0);
> +	ioport__unregister(kvm, 0x0092);
> +	ioport__unregister(kvm, 0x0040);
> +	ioport__unregister(kvm, 0x0020);
> +	ioport__unregister(kvm, 0x0000);
> +
> +	return 0;
> +}
> +dev_base_exit(ioport__remove_arch);

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

* Re: [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function
  2020-12-10 14:28 ` [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function Andre Przywara
@ 2021-02-11 12:05   ` Alexandru Elisei
  2021-02-11 17:45     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 12:05 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> At the moment we use the .generate_fdt_node member of the ioport ops
> structure to store the function pointer for the FDT node generator
> function. ioport__register() will then put a wrapper and this pointer
> into the device header.
> The serial device is the only device making use of this special ioport
> feature, so let's move this over to using the device header directly.
>
> This will allow us to get rid of this .generate_fdt_node member in the
> ops and simplify the code.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/serial.c       | 49 +++++++++++++++++++++++++++++++++++++----------
>  include/kvm/kvm.h |  2 ++
>  2 files changed, 41 insertions(+), 10 deletions(-)
>
> diff --git a/hw/serial.c b/hw/serial.c
> index 13c4663e..b0465d99 100644
> --- a/hw/serial.c
> +++ b/hw/serial.c
> @@ -23,6 +23,7 @@
>  #define UART_IIR_TYPE_BITS	0xc0
>  
>  struct serial8250_device {
> +	struct device_header	dev_hdr;
>  	struct mutex		mutex;
>  	u8			id;
>  
> @@ -53,9 +54,20 @@ struct serial8250_device {
>  	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
>  	.mcr			= UART_MCR_OUT2,
>  
> +#ifdef CONFIG_HAS_LIBFDT
> +static
> +void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> +				  fdt_irq_fn irq_fn);
> +#else
> +#define serial8250_generate_fdt_node	NULL
> +#endif
>  static struct serial8250_device devices[] = {
>  	/* ttyS0 */
>  	[0]	= {
> +		.dev_hdr = {
> +			.bus_type	= DEVICE_BUS_IOPORT,
> +			.data		= serial8250_generate_fdt_node,
> +		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 0,
> @@ -66,6 +78,10 @@ static struct serial8250_device devices[] = {
>  	},
>  	/* ttyS1 */
>  	[1]	= {
> +		.dev_hdr = {
> +			.bus_type	= DEVICE_BUS_IOPORT,
> +			.data		= serial8250_generate_fdt_node,
> +		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 1,
> @@ -76,6 +92,10 @@ static struct serial8250_device devices[] = {
>  	},
>  	/* ttyS2 */
>  	[2]	= {
> +		.dev_hdr = {
> +			.bus_type	= DEVICE_BUS_IOPORT,
> +			.data		= serial8250_generate_fdt_node,
> +		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 2,
> @@ -86,6 +106,10 @@ static struct serial8250_device devices[] = {
>  	},
>  	/* ttyS3 */
>  	[3]	= {
> +		.dev_hdr = {
> +			.bus_type	= DEVICE_BUS_IOPORT,
> +			.data		= serial8250_generate_fdt_node,
> +		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 3,
> @@ -371,13 +395,14 @@ char *fdt_stdout_path = NULL;
>  
>  #define DEVICE_NAME_MAX_LEN 32
>  static
> -void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
> -				  void (*generate_irq_prop)(void *fdt,
> -							    u8 irq,
> -							    enum irq_type))
> +void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> +				  fdt_irq_fn irq_fn)
>  {
>  	char dev_name[DEVICE_NAME_MAX_LEN];
> -	struct serial8250_device *dev = ioport->priv;
> +	struct serial8250_device *dev = container_of(dev_hdr,
> +						     struct serial8250_device,
> +						     dev_hdr);
> +
>  	u64 addr = KVM_IOPORT_AREA + dev->iobase;
>  	u64 reg_prop[] = {
>  		cpu_to_fdt64(addr),
> @@ -395,24 +420,26 @@ void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
>  	_FDT(fdt_begin_node(fdt, dev_name));
>  	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
>  	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
> -	generate_irq_prop(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
> +	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
>  	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
>  	_FDT(fdt_end_node(fdt));
>  }
> -#else
> -#define serial8250_generate_fdt_node	NULL
>  #endif
>  
>  static struct ioport_operations serial8250_ops = {
>  	.io_in			= serial8250_in,
>  	.io_out			= serial8250_out,
> -	.generate_fdt_node	= serial8250_generate_fdt_node,
>  };
>  
> -static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
> +static int serial8250__device_init(struct kvm *kvm,
> +				   struct serial8250_device *dev)
>  {
>  	int r;
>  
> +	r = device__register(&dev->dev_hdr);
> +	if (r < 0)
> +		return r;
> +
>  	ioport__map_irq(&dev->irq);
>  	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);

It's unfortunate that we now create two devices for one serial instance: one here,
and one created by ioport__register(). But I guess that's unavoidable in this
patch, and later patches will remove it.

>  
> @@ -438,6 +465,7 @@ cleanup:
>  		struct serial8250_device *dev = &devices[j];
>  
>  		ioport__unregister(kvm, dev->iobase);
> +		device__unregister(&dev->dev_hdr);
>  	}
>  
>  	return r;
> @@ -455,6 +483,7 @@ int serial8250__exit(struct kvm *kvm)
>  		r = ioport__unregister(kvm, dev->iobase);
>  		if (r < 0)
>  			return r;
> +		device__unregister(&dev->dev_hdr);
>  	}
>  
>  	return 0;
> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> index 53373b08..ee99c28e 100644
> --- a/include/kvm/kvm.h
> +++ b/include/kvm/kvm.h
> @@ -31,6 +31,8 @@
>  	.name = #ext,			\
>  	.code = ext
>  
> +typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);

Shouldn't that last parameter be enum irq_type irq_type? Would you consider moving
the typedef to include/kvm/fdt.h?

Other than the nitpicks above, the patch looks sound to me. I also did a quick
test by running kvm-unit-tests:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,
Alex
> +
>  enum {
>  	KVM_VMSTATE_RUNNING,
>  	KVM_VMSTATE_PAUSED,

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

* Re: [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality
  2020-12-10 14:28 ` [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality Andre Przywara
@ 2021-02-11 14:05   ` Alexandru Elisei
  2021-02-17 15:54     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 14:05 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> The ioport routines support a special way of registering FDT node
> generator functions. There is no reason to have this separate from the
> already existing way via the device header.
>
> Now that the only user of this special ioport variety has been
> transferred, we can retire this code, to simplify ioport handling.

One comment below, but otherwise very nice cleanup.

>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/ioport.h |  4 ----
>  ioport.c             | 34 ----------------------------------
>  2 files changed, 38 deletions(-)
>
> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> index d0213541..a61038e2 100644
> --- a/include/kvm/ioport.h
> +++ b/include/kvm/ioport.h
> @@ -29,10 +29,6 @@ struct ioport {
>  struct ioport_operations {
>  	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
>  	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> -	void (*generate_fdt_node)(struct ioport *ioport, void *fdt,
> -				  void (*generate_irq_prop)(void *fdt,
> -							    u8 irq,
> -							    enum irq_type));
>  };
>  
>  void ioport__map_irq(u8 *irq);
> diff --git a/ioport.c b/ioport.c
> index 667e8386..b98836d3 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -56,7 +56,6 @@ static struct ioport *ioport_get(struct rb_root *root, u64 addr)
>  /* Called with ioport_lock held. */
>  static void ioport_unregister(struct rb_root *root, struct ioport *data)
>  {
> -	device__unregister(&data->dev_hdr);
>  	ioport_remove(root, data);
>  	free(data);
>  }
> @@ -70,30 +69,6 @@ static void ioport_put(struct rb_root *root, struct ioport *data)
>  	mutex_unlock(&ioport_lock);
>  }
>  
> -#ifdef CONFIG_HAS_LIBFDT
> -static void generate_ioport_fdt_node(void *fdt,
> -				     struct device_header *dev_hdr,
> -				     void (*generate_irq_prop)(void *fdt,
> -							       u8 irq,
> -							       enum irq_type))
> -{
> -	struct ioport *ioport = container_of(dev_hdr, struct ioport, dev_hdr);
> -	struct ioport_operations *ops = ioport->ops;
> -
> -	if (ops->generate_fdt_node)
> -		ops->generate_fdt_node(ioport, fdt, generate_irq_prop);
> -}
> -#else
> -static void generate_ioport_fdt_node(void *fdt,
> -				     struct device_header *dev_hdr,
> -				     void (*generate_irq_prop)(void *fdt,
> -							       u8 irq,
> -							       enum irq_type))
> -{
> -	die("Unable to generate device tree nodes without libfdt\n");
> -}
> -#endif
> -
>  int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
>  {
>  	struct ioport *entry;
> @@ -107,10 +82,6 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
>  		.node		= RB_INT_INIT(port, port + count),
>  		.ops		= ops,
>  		.priv		= param,
> -		.dev_hdr	= (struct device_header) {
> -			.bus_type	= DEVICE_BUS_IOPORT,
> -			.data		= generate_ioport_fdt_node,
> -		},

Since the dev_hdr field is not used anymore, maybe it could also be removed from
struct ioport in include/kvm/ioport.h?

Thanks,

Alex

>  		/*
>  		 * Start from 0 because ioport__unregister() doesn't decrement
>  		 * the reference count.
> @@ -123,15 +94,10 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
>  	r = ioport_insert(&ioport_tree, entry);
>  	if (r < 0)
>  		goto out_free;
> -	r = device__register(&entry->dev_hdr);
> -	if (r < 0)
> -		goto out_remove;
>  	mutex_unlock(&ioport_lock);
>  
>  	return port;
>  
> -out_remove:
> -	ioport_remove(&ioport_tree, entry);
>  out_free:
>  	free(entry);
>  	mutex_unlock(&ioport_lock);

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

* Re: [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation
  2020-12-10 14:28 ` [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation Andre Przywara
@ 2021-02-11 16:10   ` Alexandru Elisei
  2021-02-17 17:43     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 16:10 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> In their core functionality MMIO and I/O port traps are not really
> different, yet we still have two totally separate code paths for
> handling them. Devices need to decide on one conduit or need to provide
> different handler functions for each of them.
>
> Extend the existing MMIO emulation to also cover ioport handlers.
> This just adds another RB tree root for holding the I/O port handlers,
> but otherwise uses the same tree population and lookup code.

Maybe I'm missing something, but why two trees? Is it valid to have an overlap
between IO port and MMIO emulation? Or was it done to make the removal of ioport
emulation easier?

If it's not valid to have that overlap, then I think having one tree for both
would better. Struct mmio_mapping would have to be augmented with a flags field
that holds the same flags given to kvm__register_iotrap to differentiate between
the two slightly different emulations. Saving the IOTRAP_COALESCE flag would also
make it trivial to call KVM_UNREGISTER_COALESCED_MMIO in kvm__deregister_iotrap,
which we currently don't do.

> "ioport" or "mmio" just become a flag in the registration function.
> Provide wrappers to not break existing users, and allow an easy
> transition for the existing ioport handlers.
>
> This also means that ioport handlers now can use the same emulation
> callback prototype as MMIO handlers, which means we have to migrate them
> over. To allow a smooth transition, we hook up the new I/O emulate
> function to the end of the existing ioport emulation code.

I'm sorry, but I don't understand that last sentence. Do you mean that the ioport
emulation code has been modified to use kvm__emulate_pio() as a fallback for when
the port is not found in the ioport_tree?

>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  include/kvm/kvm.h | 42 +++++++++++++++++++++++++++++----
>  ioport.c          |  4 ++--
>  mmio.c            | 59 +++++++++++++++++++++++++++++++++++++++--------
>  3 files changed, 89 insertions(+), 16 deletions(-)
>
> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> index ee99c28e..14f9d58b 100644
> --- a/include/kvm/kvm.h
> +++ b/include/kvm/kvm.h
> @@ -27,10 +27,16 @@
>  #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
>  #endif
>  
> +#define IOTRAP_BUS_MASK		0xf

It's not immediately obvious what this mask does. It turns out it's used to mask
the enum flags defined in the header devices.h, header which is not included in
this file.

The flag names we pass to kvm__register_iotrap() are slightly inconsistent
(DEVICE_BUS_PCI, DEVICE_BUS_MMIO and IOTRAP_COALESCE), where DEVICE_BUS_{PCI,
MMIO} come from devices.h as an enum. I was wondering if I'm missing something and
there is a particular reason why we don't define our own flags for that here
(something like IOTRAP_PIO and IOTRAP_MMIO).

If we do decide to keep the flags from devices.h, I think it would be worth it to
have a compile time check (with BUILD_BUG_ON) that IOTRAP_BUS_MASK is >=
DEVICES_BUS_MAX, which would also be a good indication of where those flags are
coming from.

> +#define IOTRAP_COALESCE		(1U << 4)
> +
>  #define DEFINE_KVM_EXT(ext)		\
>  	.name = #ext,			\
>  	.code = ext
>  
> +struct kvm_cpu;
> +typedef void (*mmio_handler_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +				u32 len, u8 is_write, void *ptr);
>  typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);
>  
>  enum {
> @@ -113,6 +119,8 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
>  void kvm__irq_trigger(struct kvm *kvm, int irq);
>  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
>  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
> +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> +		      int direction, int size, u32 count);
>  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
>  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
>  		      enum kvm_mem_type type);
> @@ -136,10 +144,36 @@ static inline int kvm__reserve_mem(struct kvm *kvm, u64 guest_phys, u64 size)
>  				 KVM_MEM_TYPE_RESERVED);
>  }
>  
> -int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
> -				    void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
> -				    void *ptr);
> -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
> +int __must_check kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 len,
> +				      mmio_handler_fn mmio_fn, void *ptr,
> +				      unsigned int flags);
> +
> +static inline
> +int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr,
> +				    u64 phys_addr_len, bool coalesce,
> +				    mmio_handler_fn mmio_fn, void *ptr)
> +{
> +	return kvm__register_iotrap(kvm, phys_addr, phys_addr_len, mmio_fn, ptr,
> +			DEVICE_BUS_MMIO | (coalesce ? IOTRAP_COALESCE : 0));
> +}
> +static inline
> +int __must_check kvm__register_pio(struct kvm *kvm, u16 port, u16 len,
> +				   mmio_handler_fn mmio_fn, void *ptr)
> +{
> +	return kvm__register_iotrap(kvm, port, len, mmio_fn, ptr,
> +				    DEVICE_BUS_IOPORT);
> +}
> +
> +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags);
> +static inline bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
> +{
> +	return kvm__deregister_iotrap(kvm, phys_addr, DEVICE_BUS_MMIO);
> +}
> +static inline bool kvm__deregister_pio(struct kvm *kvm, u16 port)
> +{
> +	return kvm__deregister_iotrap(kvm, port, DEVICE_BUS_IOPORT);
> +}
> +
>  void kvm__reboot(struct kvm *kvm);
>  void kvm__pause(struct kvm *kvm);
>  void kvm__continue(struct kvm *kvm);
> diff --git a/ioport.c b/ioport.c
> index b98836d3..204d8103 100644
> --- a/ioport.c
> +++ b/ioport.c
> @@ -147,7 +147,8 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
>  
>  	entry = ioport_get(&ioport_tree, port);
>  	if (!entry)
> -		goto out;
> +		return kvm__emulate_pio(vcpu, port, data, direction,
> +					size, count);

I have to admit this gave me pause because this patch doesn't add any users for
kvm__register_pio() (although with this change the behaviour of kvm__emulate_io()
remains exactly the same). Do you think this change would fit better in patch #7,
where the first user for kvm__register_pio() is added, or do you prefer it here?

>  
>  	ops	= entry->ops;
>  
> @@ -162,7 +163,6 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
>  
>  	ioport_put(&ioport_tree, entry);
>  
> -out:
>  	if (ret)
>  		return true;
>  
> diff --git a/mmio.c b/mmio.c
> index cd141cd3..4cce1901 100644
> --- a/mmio.c
> +++ b/mmio.c
> @@ -19,13 +19,14 @@ static DEFINE_MUTEX(mmio_lock);
>  
>  struct mmio_mapping {
>  	struct rb_int_node	node;
> -	void			(*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
> +	mmio_handler_fn		mmio_fn;
>  	void			*ptr;
>  	u32			refcount;
>  	bool			remove;
>  };
>  
>  static struct rb_root mmio_tree = RB_ROOT;
> +static struct rb_root pio_tree = RB_ROOT;
>  
>  static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
>  {
> @@ -103,9 +104,9 @@ static void mmio_put(struct kvm *kvm, struct rb_root *root, struct mmio_mapping
>  	mutex_unlock(&mmio_lock);
>  }
>  
> -int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
> -		       void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
> -			void *ptr)
> +int kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len,
> +			 mmio_handler_fn mmio_fn, void *ptr,
> +			 unsigned int flags)
>  {
>  	struct mmio_mapping *mmio;
>  	struct kvm_coalesced_mmio_zone zone;
> @@ -127,7 +128,7 @@ int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool c
>  		.remove		= false,
>  	};
>  
> -	if (coalesce) {
> +	if (flags & IOTRAP_COALESCE) {

There is no such flag being used in ioport.c, is it valid to have the flags
DEVICE_BUS_IOPORT and IOTRAP_COALESCE set at the same time?

>  		zone = (struct kvm_coalesced_mmio_zone) {
>  			.addr	= phys_addr,
>  			.size	= phys_addr_len,
> @@ -139,18 +140,27 @@ int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool c
>  		}
>  	}
>  	mutex_lock(&mmio_lock);
> -	ret = mmio_insert(&mmio_tree, mmio);
> +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
> +		ret = mmio_insert(&pio_tree, mmio);
> +	else
> +		ret = mmio_insert(&mmio_tree, mmio);
>  	mutex_unlock(&mmio_lock);
>  
>  	return ret;
>  }
>  
> -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
> +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags)
>  {
>  	struct mmio_mapping *mmio;
> +	struct rb_root *tree;
> +
> +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
> +		tree = &pio_tree;
> +	else
> +		tree = &mmio_tree;
>  
>  	mutex_lock(&mmio_lock);
> -	mmio = mmio_search_single(&mmio_tree, phys_addr);
> +	mmio = mmio_search_single(tree, phys_addr);
>  	if (mmio == NULL) {
>  		mutex_unlock(&mmio_lock);
>  		return false;
> @@ -167,7 +177,7 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
>  	 * called mmio_put(). This will trigger use-after-free errors on VCPU0.
>  	 */
>  	if (mmio->refcount == 0)
> -		mmio_deregister(kvm, &mmio_tree, mmio);
> +		mmio_deregister(kvm, tree, mmio);
>  	else
>  		mmio->remove = true;
>  	mutex_unlock(&mmio_lock);
> @@ -175,7 +185,8 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
>  	return true;
>  }
>  
> -bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write)
> +bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data,
> +		       u32 len, u8 is_write)

I don't think style changes should be part of this patch, the patch is large
enough as it is.

Thanks,

Alex

>  {
>  	struct mmio_mapping *mmio;
>  
> @@ -194,3 +205,31 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u
>  out:
>  	return true;
>  }
> +
> +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> +		     int direction, int size, u32 count)
> +{
> +	struct mmio_mapping *mmio;
> +	bool is_write = direction == KVM_EXIT_IO_OUT;
> +
> +	mmio = mmio_get(&pio_tree, port, size);
> +	if (!mmio) {
> +		if (vcpu->kvm->cfg.ioport_debug) {
> +			fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n",
> +				to_direction(direction), port, size, count);
> +
> +			return false;
> +		}
> +		return true;
> +	}
> +
> +	while (count--) {
> +		mmio->mmio_fn(vcpu, port, data, size, is_write, mmio->ptr);
> +
> +		data += size;
> +	}
> +
> +	mmio_put(vcpu->kvm, &pio_tree, mmio);
> +
> +	return true;
> +}

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

* Re: [PATCH kvmtool 05/21] hw/i8042: Clean up data types
  2020-12-10 14:28 ` [PATCH kvmtool 05/21] hw/i8042: Clean up data types Andre Przywara
@ 2021-02-11 16:55   ` Alexandru Elisei
  2021-02-17 17:46     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 16:55 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:

> The i8042 is clearly an 8-bit era device, so there is little room for
> 32-bit registers.
> Clean up the data types used.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/i8042.c | 20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/hw/i8042.c b/hw/i8042.c
> index 37a99a2d..36ee183f 100644
> --- a/hw/i8042.c
> +++ b/hw/i8042.c
> @@ -64,11 +64,11 @@
>  struct kbd_state {
>  	struct kvm		*kvm;
>  
> -	char			kq[QUEUE_SIZE];	/* Keyboard queue */
> +	u8			kq[QUEUE_SIZE];	/* Keyboard queue */
>  	int			kread, kwrite;	/* Indexes into the queue */
>  	int			kcount;		/* number of elements in queue */
>  
> -	char			mq[QUEUE_SIZE];
> +	u8			mq[QUEUE_SIZE];
>  	int			mread, mwrite;
>  	int			mcount;

I think the write_cmd field further down should also be u8 because it stores the
first byte of a command (and it's set only to an 8 bit value in kbd_write_command()).

Otherwise, it looks ok to me. osdev wiki seems to confirm that the device is
indeed 8 bit only, and all the registers are 8 bit now:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

>  
> @@ -173,9 +173,9 @@ static void kbd_write_command(struct kvm *kvm, u8 val)
>  /*
>   * Called when the OS reads from port 0x60 (PS/2 data)
>   */
> -static u32 kbd_read_data(void)
> +static u8 kbd_read_data(void)
>  {
> -	u32 ret;
> +	u8 ret;
>  	int i;
>  
>  	if (state.kcount != 0) {
> @@ -202,9 +202,9 @@ static u32 kbd_read_data(void)
>  /*
>   * Called when the OS read from port 0x64, the command port
>   */
> -static u32 kbd_read_status(void)
> +static u8 kbd_read_status(void)
>  {
> -	return (u32)state.status;
> +	return state.status;
>  }
>  
>  /*
> @@ -212,7 +212,7 @@ static u32 kbd_read_status(void)
>   * Things written here are generally arguments to commands previously
>   * written to port 0x64 and stored in state.write_cmd
>   */
> -static void kbd_write_data(u32 val)
> +static void kbd_write_data(u8 val)
>  {
>  	switch (state.write_cmd) {
>  	case I8042_CMD_CTL_WCTR:
> @@ -304,8 +304,8 @@ static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *
>  		break;
>  	}
>  	case I8042_DATA_REG: {
> -		u32 value = kbd_read_data();
> -		ioport__write32(data, value);
> +		u8 value = kbd_read_data();
> +		ioport__write8(data, value);
>  		break;
>  	}
>  	case I8042_PORT_B_REG: {
> @@ -328,7 +328,7 @@ static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void
>  		break;
>  	}
>  	case I8042_DATA_REG: {
> -		u32 value = ioport__read32(data);
> +		u8 value = ioport__read8(data);
>  		kbd_write_data(value);
>  		break;
>  	}

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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2021-02-10 17:44   ` Alexandru Elisei
@ 2021-02-11 17:16     ` Andre Przywara
  2021-02-11 17:32       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-11 17:16 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Wed, 10 Feb 2021 17:44:59 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi Alex,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > Since x86 had a special need for registering tons of special I/O ports,
> > we had an ioport__setup_arch() callback, to allow each architecture
> > to do the same. As it turns out no one uses it beside x86, so we remove
> > that unnecessary abstraction.
> >
> > The generic function was registered via a device_base_init() call, so
> > we just do the same for the x86 specific function only, and can remove
> > the unneeded ioport__setup_arch().
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  arm/ioport.c         |  5 -----
> >  include/kvm/ioport.h |  1 -
> >  ioport.c             | 28 ----------------------------
> >  mips/kvm.c           |  5 -----
> >  powerpc/ioport.c     |  6 ------
> >  x86/ioport.c         | 25 ++++++++++++++++++++++++-
> >  6 files changed, 24 insertions(+), 46 deletions(-)
> >
> > diff --git a/arm/ioport.c b/arm/ioport.c
> > index 2f0feb9a..24092c9d 100644
> > --- a/arm/ioport.c
> > +++ b/arm/ioport.c
> > @@ -1,11 +1,6 @@
> >  #include "kvm/ioport.h"
> >  #include "kvm/irq.h"
> >  
> > -int ioport__setup_arch(struct kvm *kvm)
> > -{
> > -	return 0;
> > -}
> > -
> >  void ioport__map_irq(u8 *irq)
> >  {
> >  	*irq = irq__alloc_line();
> > diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> > index 039633f7..d0213541 100644
> > --- a/include/kvm/ioport.h
> > +++ b/include/kvm/ioport.h
> > @@ -35,7 +35,6 @@ struct ioport_operations {
> >  							    enum irq_type));
> >  };
> >  
> > -int ioport__setup_arch(struct kvm *kvm);
> >  void ioport__map_irq(u8 *irq);
> >  
> >  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> > diff --git a/ioport.c b/ioport.c
> > index 844a832d..667e8386 100644
> > --- a/ioport.c
> > +++ b/ioport.c
> > @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
> >  	return 0;
> >  }
> >  
> > -static void ioport__unregister_all(void)
> > -{
> > -	struct ioport *entry;
> > -	struct rb_node *rb;
> > -	struct rb_int_node *rb_node;
> > -
> > -	rb = rb_first(&ioport_tree);
> > -	while (rb) {
> > -		rb_node = rb_int(rb);
> > -		entry = ioport_node(rb_node);
> > -		ioport_unregister(&ioport_tree, entry);
> > -		rb = rb_first(&ioport_tree);
> > -	}
> > -}  
> 
> I get the impression this is a rebasing artifact. The commit message doesn't
> mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
> far as I can tell it's still needed because there are places other than
> ioport__setup_arch() from where ioport__register() is called.

I agree that the commit message is a bit thin on this fact, but the
functionality of ioport__unregister_all() is now in
x86/ioport.c:ioport__remove_arch(). I think removing ioport__init()
without removing ioport__exit() as well would look very weird, if not
hackish.

I can amend the commit message to mention this, or is there anything
else I missed?

Cheers,
Andre

> 
> > -
> >  static const char *to_direction(int direction)
> >  {
> >  	if (direction == KVM_EXIT_IO_IN)
> > @@ -220,16 +205,3 @@ out:
> >  
> >  	return !kvm->cfg.ioport_debug;
> >  }
> > -
> > -int ioport__init(struct kvm *kvm)
> > -{
> > -	return ioport__setup_arch(kvm);
> > -}
> > -dev_base_init(ioport__init);
> > -
> > -int ioport__exit(struct kvm *kvm)
> > -{
> > -	ioport__unregister_all();
> > -	return 0;
> > -}
> > -dev_base_exit(ioport__exit);
> > diff --git a/mips/kvm.c b/mips/kvm.c
> > index 26355930..e110e5d5 100644
> > --- a/mips/kvm.c
> > +++ b/mips/kvm.c
> > @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
> >  		die_perror("KVM_IRQ_LINE ioctl");
> >  }
> >  
> > -int ioport__setup_arch(struct kvm *kvm)
> > -{
> > -	return 0;
> > -}
> > -
> >  bool kvm__arch_cpu_supports_vm(void)
> >  {
> >  	return true;
> > diff --git a/powerpc/ioport.c b/powerpc/ioport.c
> > index 0c188b61..a5cff4ee 100644
> > --- a/powerpc/ioport.c
> > +++ b/powerpc/ioport.c
> > @@ -12,12 +12,6 @@
> >  
> >  #include <stdlib.h>
> >  
> > -int ioport__setup_arch(struct kvm *kvm)
> > -{
> > -	/* PPC has no legacy ioports to set up */
> > -	return 0;
> > -}
> > -
> >  void ioport__map_irq(u8 *irq)
> >  {
> >  }
> > diff --git a/x86/ioport.c b/x86/ioport.c
> > index 7ad7b8f3..8c5c7699 100644
> > --- a/x86/ioport.c
> > +++ b/x86/ioport.c
> > @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
> >  {
> >  }
> >  
> > -int ioport__setup_arch(struct kvm *kvm)
> > +static int ioport__setup_arch(struct kvm *kvm)
> >  {
> >  	int r;
> >  
> > @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
> >  
> >  	return 0;
> >  }
> > +dev_base_init(ioport__setup_arch);
> > +
> > +static int ioport__remove_arch(struct kvm *kvm)
> > +{
> > +	ioport__unregister(kvm, 0x510);
> > +	ioport__unregister(kvm, 0x402);
> > +	ioport__unregister(kvm, 0x03D5);
> > +	ioport__unregister(kvm, 0x03D4);
> > +	ioport__unregister(kvm, 0x0378);
> > +	ioport__unregister(kvm, 0x0278);
> > +	ioport__unregister(kvm, 0x00F0);
> > +	ioport__unregister(kvm, 0x00ED);
> > +	ioport__unregister(kvm, IOPORT_DBG);
> > +	ioport__unregister(kvm, 0x00C0);
> > +	ioport__unregister(kvm, 0x00A0);
> > +	ioport__unregister(kvm, 0x0092);
> > +	ioport__unregister(kvm, 0x0040);
> > +	ioport__unregister(kvm, 0x0020);
> > +	ioport__unregister(kvm, 0x0000);
> > +
> > +	return 0;
> > +}
> > +dev_base_exit(ioport__remove_arch);  


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

* Re: [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2020-12-10 14:28 ` [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler Andre Przywara
@ 2021-02-11 17:23   ` Alexandru Elisei
  2021-02-18 10:34     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 17:23 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide an emulation function compatible with the MMIO
> prototype.
>
> Adjust the trap handler to use that new function, and provide shims to
> implement the old ioport interface, for now.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
>  1 file changed, 34 insertions(+), 34 deletions(-)
>
> diff --git a/hw/i8042.c b/hw/i8042.c
> index 36ee183f..eb1f9d28 100644
> --- a/hw/i8042.c
> +++ b/hw/i8042.c
> @@ -292,52 +292,52 @@ static void kbd_reset(void)
>  	};
>  }
>  
> -/*
> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> - */
> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +		   u8 is_write, void *ptr)
>  {
> -	switch (port) {
> -	case I8042_COMMAND_REG: {
> -		u8 value = kbd_read_status();
> -		ioport__write8(data, value);
> +	u8 value;
> +
> +	if (is_write)
> +		value = ioport__read8(data);
> +
> +	switch (addr) {
> +	case I8042_COMMAND_REG:
> +		if (is_write)
> +			kbd_write_command(vcpu->kvm, value);
> +		else
> +			value = kbd_read_status();
>  		break;
> -	}
> -	case I8042_DATA_REG: {
> -		u8 value = kbd_read_data();
> -		ioport__write8(data, value);
> +	case I8042_DATA_REG:
> +		if (is_write)
> +			kbd_write_data(value);
> +		else
> +			value = kbd_read_data();
>  		break;
> -	}
> -	case I8042_PORT_B_REG: {
> -		ioport__write8(data, 0x20);
> +	case I8042_PORT_B_REG:
> +		if (!is_write)
> +			value = 0x20;
>  		break;
> -	}
>  	default:
> -		return false;
> +		return;

Any particular reason for removing the false return value? I don't see it
mentioned in the commit message. Otherwise this is identical to the two functions
it replaces.

>  	}
>  
> +	if (!is_write)
> +		ioport__write8(data, value);
> +}
> +
> +/*
> + * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> + */
> +static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +{
> +	kbd_io(vcpu, port, data, size, false, NULL);

is_write is an u8, not a bool.

I never could wrap my head around the ioport convention of "in" (read) and "out"
(write). To be honest, changing is_write changed to an enum so it's crystal clear
what is happening would help with that a lot, but I guess that's a separate patch.

Thanks,

Alex

> +
>  	return true;
>  }
>  
>  static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> -	switch (port) {
> -	case I8042_COMMAND_REG: {
> -		u8 value = ioport__read8(data);
> -		kbd_write_command(vcpu->kvm, value);
> -		break;
> -	}
> -	case I8042_DATA_REG: {
> -		u8 value = ioport__read8(data);
> -		kbd_write_data(value);
> -		break;
> -	}
> -	case I8042_PORT_B_REG: {
> -		break;
> -	}
> -	default:
> -		return false;
> -	}
> +	kbd_io(vcpu, port, data, size, true, NULL);
>  
>  	return true;
>  }

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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2021-02-11 17:16     ` Andre Przywara
@ 2021-02-11 17:32       ` Alexandru Elisei
  2021-02-17 16:46         ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-11 17:32 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/11/21 5:16 PM, Andre Przywara wrote:
> On Wed, 10 Feb 2021 17:44:59 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> Hi Alex,
>
>> On 12/10/20 2:28 PM, Andre Przywara wrote:
>>> Since x86 had a special need for registering tons of special I/O ports,
>>> we had an ioport__setup_arch() callback, to allow each architecture
>>> to do the same. As it turns out no one uses it beside x86, so we remove
>>> that unnecessary abstraction.
>>>
>>> The generic function was registered via a device_base_init() call, so
>>> we just do the same for the x86 specific function only, and can remove
>>> the unneeded ioport__setup_arch().
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  arm/ioport.c         |  5 -----
>>>  include/kvm/ioport.h |  1 -
>>>  ioport.c             | 28 ----------------------------
>>>  mips/kvm.c           |  5 -----
>>>  powerpc/ioport.c     |  6 ------
>>>  x86/ioport.c         | 25 ++++++++++++++++++++++++-
>>>  6 files changed, 24 insertions(+), 46 deletions(-)
>>>
>>> diff --git a/arm/ioport.c b/arm/ioport.c
>>> index 2f0feb9a..24092c9d 100644
>>> --- a/arm/ioport.c
>>> +++ b/arm/ioport.c
>>> @@ -1,11 +1,6 @@
>>>  #include "kvm/ioport.h"
>>>  #include "kvm/irq.h"
>>>  
>>> -int ioport__setup_arch(struct kvm *kvm)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>>  void ioport__map_irq(u8 *irq)
>>>  {
>>>  	*irq = irq__alloc_line();
>>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
>>> index 039633f7..d0213541 100644
>>> --- a/include/kvm/ioport.h
>>> +++ b/include/kvm/ioport.h
>>> @@ -35,7 +35,6 @@ struct ioport_operations {
>>>  							    enum irq_type));
>>>  };
>>>  
>>> -int ioport__setup_arch(struct kvm *kvm);
>>>  void ioport__map_irq(u8 *irq);
>>>  
>>>  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
>>> diff --git a/ioport.c b/ioport.c
>>> index 844a832d..667e8386 100644
>>> --- a/ioport.c
>>> +++ b/ioport.c
>>> @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
>>>  	return 0;
>>>  }
>>>  
>>> -static void ioport__unregister_all(void)
>>> -{
>>> -	struct ioport *entry;
>>> -	struct rb_node *rb;
>>> -	struct rb_int_node *rb_node;
>>> -
>>> -	rb = rb_first(&ioport_tree);
>>> -	while (rb) {
>>> -		rb_node = rb_int(rb);
>>> -		entry = ioport_node(rb_node);
>>> -		ioport_unregister(&ioport_tree, entry);
>>> -		rb = rb_first(&ioport_tree);
>>> -	}
>>> -}  
>> I get the impression this is a rebasing artifact. The commit message doesn't
>> mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
>> far as I can tell it's still needed because there are places other than
>> ioport__setup_arch() from where ioport__register() is called.
> I agree that the commit message is a bit thin on this fact, but the
> functionality of ioport__unregister_all() is now in
> x86/ioport.c:ioport__remove_arch(). I think removing ioport__init()
> without removing ioport__exit() as well would look very weird, if not
> hackish.

Not necessarily. ioport__unregister_all() removes the ioports added by
x86/ioport.c::ioport__setup_arch(), *plus* ioports added by different devices,
like serial, rtc, virtio-pci and vfio-pci (which are used by arm/arm64).

Thanks,

Alex

>
> I can amend the commit message to mention this, or is there anything
> else I missed?
>
> Cheers,
> Andre
>
>>> -
>>>  static const char *to_direction(int direction)
>>>  {
>>>  	if (direction == KVM_EXIT_IO_IN)
>>> @@ -220,16 +205,3 @@ out:
>>>  
>>>  	return !kvm->cfg.ioport_debug;
>>>  }
>>> -
>>> -int ioport__init(struct kvm *kvm)
>>> -{
>>> -	return ioport__setup_arch(kvm);
>>> -}
>>> -dev_base_init(ioport__init);
>>> -
>>> -int ioport__exit(struct kvm *kvm)
>>> -{
>>> -	ioport__unregister_all();
>>> -	return 0;
>>> -}
>>> -dev_base_exit(ioport__exit);
>>> diff --git a/mips/kvm.c b/mips/kvm.c
>>> index 26355930..e110e5d5 100644
>>> --- a/mips/kvm.c
>>> +++ b/mips/kvm.c
>>> @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
>>>  		die_perror("KVM_IRQ_LINE ioctl");
>>>  }
>>>  
>>> -int ioport__setup_arch(struct kvm *kvm)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>>  bool kvm__arch_cpu_supports_vm(void)
>>>  {
>>>  	return true;
>>> diff --git a/powerpc/ioport.c b/powerpc/ioport.c
>>> index 0c188b61..a5cff4ee 100644
>>> --- a/powerpc/ioport.c
>>> +++ b/powerpc/ioport.c
>>> @@ -12,12 +12,6 @@
>>>  
>>>  #include <stdlib.h>
>>>  
>>> -int ioport__setup_arch(struct kvm *kvm)
>>> -{
>>> -	/* PPC has no legacy ioports to set up */
>>> -	return 0;
>>> -}
>>> -
>>>  void ioport__map_irq(u8 *irq)
>>>  {
>>>  }
>>> diff --git a/x86/ioport.c b/x86/ioport.c
>>> index 7ad7b8f3..8c5c7699 100644
>>> --- a/x86/ioport.c
>>> +++ b/x86/ioport.c
>>> @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
>>>  {
>>>  }
>>>  
>>> -int ioport__setup_arch(struct kvm *kvm)
>>> +static int ioport__setup_arch(struct kvm *kvm)
>>>  {
>>>  	int r;
>>>  
>>> @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
>>>  
>>>  	return 0;
>>>  }
>>> +dev_base_init(ioport__setup_arch);
>>> +
>>> +static int ioport__remove_arch(struct kvm *kvm)
>>> +{
>>> +	ioport__unregister(kvm, 0x510);
>>> +	ioport__unregister(kvm, 0x402);
>>> +	ioport__unregister(kvm, 0x03D5);
>>> +	ioport__unregister(kvm, 0x03D4);
>>> +	ioport__unregister(kvm, 0x0378);
>>> +	ioport__unregister(kvm, 0x0278);
>>> +	ioport__unregister(kvm, 0x00F0);
>>> +	ioport__unregister(kvm, 0x00ED);
>>> +	ioport__unregister(kvm, IOPORT_DBG);
>>> +	ioport__unregister(kvm, 0x00C0);
>>> +	ioport__unregister(kvm, 0x00A0);
>>> +	ioport__unregister(kvm, 0x0092);
>>> +	ioport__unregister(kvm, 0x0040);
>>> +	ioport__unregister(kvm, 0x0020);
>>> +	ioport__unregister(kvm, 0x0000);
>>> +
>>> +	return 0;
>>> +}
>>> +dev_base_exit(ioport__remove_arch);  

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

* Re: [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function
  2021-02-11 12:05   ` Alexandru Elisei
@ 2021-02-11 17:45     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-11 17:45 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 12:05:35 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > At the moment we use the .generate_fdt_node member of the ioport ops
> > structure to store the function pointer for the FDT node generator
> > function. ioport__register() will then put a wrapper and this pointer
> > into the device header.
> > The serial device is the only device making use of this special ioport
> > feature, so let's move this over to using the device header directly.
> >
> > This will allow us to get rid of this .generate_fdt_node member in the
> > ops and simplify the code.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/serial.c       | 49 +++++++++++++++++++++++++++++++++++++----------
> >  include/kvm/kvm.h |  2 ++
> >  2 files changed, 41 insertions(+), 10 deletions(-)
> >
> > diff --git a/hw/serial.c b/hw/serial.c
> > index 13c4663e..b0465d99 100644
> > --- a/hw/serial.c
> > +++ b/hw/serial.c
> > @@ -23,6 +23,7 @@
> >  #define UART_IIR_TYPE_BITS	0xc0
> >  
> >  struct serial8250_device {
> > +	struct device_header	dev_hdr;
> >  	struct mutex		mutex;
> >  	u8			id;
> >  
> > @@ -53,9 +54,20 @@ struct serial8250_device {
> >  	.msr			= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
> >  	.mcr			= UART_MCR_OUT2,
> >  
> > +#ifdef CONFIG_HAS_LIBFDT
> > +static
> > +void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> > +				  fdt_irq_fn irq_fn);
> > +#else
> > +#define serial8250_generate_fdt_node	NULL
> > +#endif
> >  static struct serial8250_device devices[] = {
> >  	/* ttyS0 */
> >  	[0]	= {
> > +		.dev_hdr = {
> > +			.bus_type	= DEVICE_BUS_IOPORT,
> > +			.data		= serial8250_generate_fdt_node,
> > +		},
> >  		.mutex			= MUTEX_INITIALIZER,
> >  
> >  		.id			= 0,
> > @@ -66,6 +78,10 @@ static struct serial8250_device devices[] = {
> >  	},
> >  	/* ttyS1 */
> >  	[1]	= {
> > +		.dev_hdr = {
> > +			.bus_type	= DEVICE_BUS_IOPORT,
> > +			.data		= serial8250_generate_fdt_node,
> > +		},
> >  		.mutex			= MUTEX_INITIALIZER,
> >  
> >  		.id			= 1,
> > @@ -76,6 +92,10 @@ static struct serial8250_device devices[] = {
> >  	},
> >  	/* ttyS2 */
> >  	[2]	= {
> > +		.dev_hdr = {
> > +			.bus_type	= DEVICE_BUS_IOPORT,
> > +			.data		= serial8250_generate_fdt_node,
> > +		},
> >  		.mutex			= MUTEX_INITIALIZER,
> >  
> >  		.id			= 2,
> > @@ -86,6 +106,10 @@ static struct serial8250_device devices[] = {
> >  	},
> >  	/* ttyS3 */
> >  	[3]	= {
> > +		.dev_hdr = {
> > +			.bus_type	= DEVICE_BUS_IOPORT,
> > +			.data		= serial8250_generate_fdt_node,
> > +		},
> >  		.mutex			= MUTEX_INITIALIZER,
> >  
> >  		.id			= 3,
> > @@ -371,13 +395,14 @@ char *fdt_stdout_path = NULL;
> >  
> >  #define DEVICE_NAME_MAX_LEN 32
> >  static
> > -void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
> > -				  void (*generate_irq_prop)(void *fdt,
> > -							    u8 irq,
> > -							    enum irq_type))
> > +void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> > +				  fdt_irq_fn irq_fn)
> >  {
> >  	char dev_name[DEVICE_NAME_MAX_LEN];
> > -	struct serial8250_device *dev = ioport->priv;
> > +	struct serial8250_device *dev = container_of(dev_hdr,
> > +						     struct serial8250_device,
> > +						     dev_hdr);
> > +
> >  	u64 addr = KVM_IOPORT_AREA + dev->iobase;
> >  	u64 reg_prop[] = {
> >  		cpu_to_fdt64(addr),
> > @@ -395,24 +420,26 @@ void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt,
> >  	_FDT(fdt_begin_node(fdt, dev_name));
> >  	_FDT(fdt_property_string(fdt, "compatible", "ns16550a"));
> >  	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
> > -	generate_irq_prop(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
> > +	irq_fn(fdt, dev->irq, IRQ_TYPE_LEVEL_HIGH);
> >  	_FDT(fdt_property_cell(fdt, "clock-frequency", 1843200));
> >  	_FDT(fdt_end_node(fdt));
> >  }
> > -#else
> > -#define serial8250_generate_fdt_node	NULL
> >  #endif
> >  
> >  static struct ioport_operations serial8250_ops = {
> >  	.io_in			= serial8250_in,
> >  	.io_out			= serial8250_out,
> > -	.generate_fdt_node	= serial8250_generate_fdt_node,
> >  };
> >  
> > -static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
> > +static int serial8250__device_init(struct kvm *kvm,
> > +				   struct serial8250_device *dev)
> >  {
> >  	int r;
> >  
> > +	r = device__register(&dev->dev_hdr);
> > +	if (r < 0)
> > +		return r;
> > +
> >  	ioport__map_irq(&dev->irq);
> >  	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);  
> 
> It's unfortunate that we now create two devices for one serial instance: one here,
> and one created by ioport__register(). But I guess that's unavoidable in this
> patch, and later patches will remove it.

Well, we do this already, wherever we register multiple I/O ports per
device, RTC and i8042 are an example (because we register one device
per I/O port). This really isn't a particular problem, it's just ugly,
so just get's a tiny bit more uglier for a few patches that
hopefully nobody will actually use (in anger).

> 
> >  
> > @@ -438,6 +465,7 @@ cleanup:
> >  		struct serial8250_device *dev = &devices[j];
> >  
> >  		ioport__unregister(kvm, dev->iobase);
> > +		device__unregister(&dev->dev_hdr);
> >  	}
> >  
> >  	return r;
> > @@ -455,6 +483,7 @@ int serial8250__exit(struct kvm *kvm)
> >  		r = ioport__unregister(kvm, dev->iobase);
> >  		if (r < 0)
> >  			return r;
> > +		device__unregister(&dev->dev_hdr);
> >  	}
> >  
> >  	return 0;
> > diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> > index 53373b08..ee99c28e 100644
> > --- a/include/kvm/kvm.h
> > +++ b/include/kvm/kvm.h
> > @@ -31,6 +31,8 @@
> >  	.name = #ext,			\
> >  	.code = ext
> >  
> > +typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);  
> 
> Shouldn't that last parameter be enum irq_type irq_type? Would you consider moving
> the typedef to include/kvm/fdt.h?

I think where I came from was that typedef's don't need parameter names,
just the type. But just having (void *, u8, enum irq_type) is really
hard to understand, so I added parameter names where this helps. "enum
irq_type irq_type" looks redundant, but I can certainly add this for
consistency.

> Other than the nitpicks above, the patch looks sound to me. I also did a quick
> test by running kvm-unit-tests:
> 
> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks!

Andre

> 
> Thanks,
> Alex
> > +
> >  enum {
> >  	KVM_VMSTATE_RUNNING,
> >  	KVM_VMSTATE_PAUSED,  


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

* Re: [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers
  2020-12-10 14:28 ` [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers Andre Przywara
@ 2021-02-12 10:41   ` Alexandru Elisei
  2021-02-18 12:09     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 10:41 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> Now that the PC keyboard has a trap handler adhering to the MMIO fault
> handler prototype, let's switch over to the joint registration routine.
>
> This allows us to get rid of the ioport shim routines.
>
> Make the kbd_init() function static on the way.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/i8042.c          | 30 ++++--------------------------
>  include/kvm/i8042.h |  1 -
>  2 files changed, 4 insertions(+), 27 deletions(-)
>
> diff --git a/hw/i8042.c b/hw/i8042.c
> index eb1f9d28..91d79dc4 100644
> --- a/hw/i8042.c
> +++ b/hw/i8042.c
> @@ -325,40 +325,18 @@ static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  		ioport__write8(data, value);
>  }
>  
> -/*
> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> - */
> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	kbd_io(vcpu, port, data, size, false, NULL);
> -
> -	return true;
> -}
> -
> -static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	kbd_io(vcpu, port, data, size, true, NULL);
> -
> -	return true;
> -}
> -
> -static struct ioport_operations kbd_ops = {
> -	.io_in		= kbd_in,
> -	.io_out		= kbd_out,
> -};
> -
> -int kbd__init(struct kvm *kvm)
> +static int kbd__init(struct kvm *kvm)
>  {
>  	int r;
>  
>  	kbd_reset();
>  	state.kvm = kvm;
> -	r = ioport__register(kvm, I8042_DATA_REG, &kbd_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, I8042_DATA_REG, 2, kbd_io, NULL);

I guess you are registering two addresses here to cover I8042_PORT_B_REG, right?
Might be worth a comment.

>  	if (r < 0)
>  		return r;
> -	r = ioport__register(kvm, I8042_COMMAND_REG, &kbd_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, I8042_COMMAND_REG, 2, kbd_io, NULL);

Shouldn't length be 1? The emulation should work only for address 0x64
(command/status register), right? Or am I missing something?

Thanks,

Alex

>  	if (r < 0) {
> -		ioport__unregister(kvm, I8042_DATA_REG);
> +		kvm__deregister_pio(kvm, I8042_DATA_REG);
>  		return r;
>  	}
>  
> diff --git a/include/kvm/i8042.h b/include/kvm/i8042.h
> index 3b4ab688..cd4ae6bb 100644
> --- a/include/kvm/i8042.h
> +++ b/include/kvm/i8042.h
> @@ -7,6 +7,5 @@ struct kvm;
>  
>  void mouse_queue(u8 c);
>  void kbd_queue(u8 c);
> -int kbd__init(struct kvm *kvm);
>  
>  #endif

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

* Re: [PATCH kvmtool 08/21] x86/ioport: Refactor trap handlers
  2020-12-10 14:28 ` [PATCH kvmtool 08/21] x86/ioport: Refactor " Andre Przywara
@ 2021-02-12 11:14   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 11:14 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide emulation functions compatible with the MMIO
> prototype.
>
> Adjust the trap handlers to use that new function, and provide shims to
> implement the old ioport interface, for now.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  x86/ioport.c | 30 ++++++++++++++++++++++++++----
>  1 file changed, 26 insertions(+), 4 deletions(-)
>
> diff --git a/x86/ioport.c b/x86/ioport.c
> index 8c5c7699..932da20a 100644
> --- a/x86/ioport.c
> +++ b/x86/ioport.c
> @@ -3,8 +3,14 @@
>  #include <stdlib.h>
>  #include <stdio.h>
>  
> +static void dummy_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +		       u8 is_write, void *ptr)
> +{
> +}
> +
>  static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> +	dummy_mmio(vcpu, port, data, size, true, NULL);
>  	return 0;
>  }
>  
> @@ -12,15 +18,23 @@ static struct ioport_operations debug_ops = {
>  	.io_out		= debug_io_out,
>  };
>  
> -static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +			       u32 len, u8 is_write, void *ptr)
>  {
>  	char ch;
>  
> +	if (!is_write)
> +		return;
> +
>  	ch = ioport__read8(data);
>  
>  	putchar(ch);
> +}
>  
> -	return true;
> +static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +{
> +	seabios_debug_mmio(vcpu, port, data, size, true, NULL);
> +	return 0;
>  }
>  
>  static struct ioport_operations seabios_debug_ops = {
> @@ -29,11 +43,13 @@ static struct ioport_operations seabios_debug_ops = {
>  
>  static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> +	dummy_mmio(vcpu, port, data, size, false, NULL);
>  	return true;
>  }
>  
>  static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> +	dummy_mmio(vcpu, port, data, size, true, NULL);
>  	return true;
>  }
>  
> @@ -50,13 +66,19 @@ static struct ioport_operations dummy_write_only_ioport_ops = {
>   * The "fast A20 gate"
>   */
>  
> -static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void ps2_control_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +			     u8 is_write, void *ptr)
>  {
>  	/*
>  	 * A20 is always enabled.
>  	 */
> -	ioport__write8(data, 0x02);
> +	if (!is_write)
> +		ioport__write8(data, 0x02);
> +}
>  
> +static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +{
> +	ps2_control_mmio(vcpu, port, data, size, false, NULL);
>  	return true;
>  }
>  

Looks correct to me, if not particularly pretty; thankfully the next patch removes
all of these dummy functions. It compiles, so:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex


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

* Re: [PATCH kvmtool 09/21] x86/ioport: Switch to new trap handlers
  2020-12-10 14:28 ` [PATCH kvmtool 09/21] x86/ioport: Switch to new " Andre Przywara
@ 2021-02-12 11:27   ` Alexandru Elisei
  2021-02-18 14:05     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 11:27 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> Now that the x86 I/O ports have trap handlers adhering to the MMIO fault
> handler prototype, let's switch over to the joint registration routine.
>
> This allows us to get rid of the ioport shim routines.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  x86/ioport.c | 113 ++++++++++++++-------------------------------------
>  1 file changed, 30 insertions(+), 83 deletions(-)
>
> diff --git a/x86/ioport.c b/x86/ioport.c
> index 932da20a..87955da1 100644
> --- a/x86/ioport.c
> +++ b/x86/ioport.c
> @@ -8,16 +8,6 @@ static void dummy_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  {
>  }
>  
> -static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	dummy_mmio(vcpu, port, data, size, true, NULL);
> -	return 0;
> -}

0 is false in boolean logic, which means that emulation fails according to the
(old) ioport emulation code (ioport.c::kvm__emulate_io()).

So I guess I have a few questions:

- Is this a bug in the emulation code, where the author thought that
debug_io_out() returns an int, and in that case 0 actually means success?

- If writing to the debug port is rightfully considered an error, do we care
enough about it to print something to stdout like kvm__emulate_io() does when
debug_io_out() returns false?

Thanks,

Alex

> -
> -static struct ioport_operations debug_ops = {
> -	.io_out		= debug_io_out,
> -};
> -
>  static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>  			       u32 len, u8 is_write, void *ptr)
>  {
> @@ -31,37 +21,6 @@ static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>  	putchar(ch);
>  }
>  
> -static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	seabios_debug_mmio(vcpu, port, data, size, true, NULL);
> -	return 0;
> -}
> -
> -static struct ioport_operations seabios_debug_ops = {
> -	.io_out		= seabios_debug_io_out,
> -};
> -
> -static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	dummy_mmio(vcpu, port, data, size, false, NULL);
> -	return true;
> -}
> -
> -static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	dummy_mmio(vcpu, port, data, size, true, NULL);
> -	return true;
> -}
> -
> -static struct ioport_operations dummy_read_write_ioport_ops = {
> -	.io_in		= dummy_io_in,
> -	.io_out		= dummy_io_out,
> -};
> -
> -static struct ioport_operations dummy_write_only_ioport_ops = {
> -	.io_out		= dummy_io_out,
> -};
> -
>  /*
>   * The "fast A20 gate"
>   */
> @@ -76,17 +35,6 @@ static void ps2_control_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  		ioport__write8(data, 0x02);
>  }
>  
> -static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	ps2_control_mmio(vcpu, port, data, size, false, NULL);
> -	return true;
> -}
> -
> -static struct ioport_operations ps2_control_a_ops = {
> -	.io_in		= ps2_control_a_io_in,
> -	.io_out		= dummy_io_out,
> -};
> -
>  void ioport__map_irq(u8 *irq)
>  {
>  }
> @@ -98,75 +46,75 @@ static int ioport__setup_arch(struct kvm *kvm)
>  	/* Legacy ioport setup */
>  
>  	/* 0000 - 001F - DMA1 controller */
> -	r = ioport__register(kvm, 0x0000, &dummy_read_write_ioport_ops, 32, NULL);
> +	r = kvm__register_pio(kvm, 0x0000, 32, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 0x0020 - 0x003F - 8259A PIC 1 */
> -	r = ioport__register(kvm, 0x0020, &dummy_read_write_ioport_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, 0x0020, 2, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
> -	r = ioport__register(kvm, 0x0040, &dummy_read_write_ioport_ops, 4, NULL);
> +	r = kvm__register_pio(kvm, 0x0040, 4, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 0092 - PS/2 system control port A */
> -	r = ioport__register(kvm, 0x0092, &ps2_control_a_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, 0x0092, 1, ps2_control_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 0x00A0 - 0x00AF - 8259A PIC 2 */
> -	r = ioport__register(kvm, 0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, 0x00A0, 2, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 00C0 - 001F - DMA2 controller */
> -	r = ioport__register(kvm, 0x00C0, &dummy_read_write_ioport_ops, 32, NULL);
> +	r = kvm__register_pio(kvm, 0x00c0, 32, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 00E0-00EF are 'motherboard specific' so we use them for our
>  	   internal debugging purposes.  */
> -	r = ioport__register(kvm, IOPORT_DBG, &debug_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, IOPORT_DBG, 1, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 00ED - DUMMY PORT FOR DELAY??? */
> -	r = ioport__register(kvm, 0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, 0x00ed, 1, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 0x00F0 - 0x00FF - Math co-processor */
> -	r = ioport__register(kvm, 0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, 0x00f0, 2, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 0278-027A - PARALLEL PRINTER PORT (usually LPT1, sometimes LPT2) */
> -	r = ioport__register(kvm, 0x0278, &dummy_read_write_ioport_ops, 3, NULL);
> +	r = kvm__register_pio(kvm, 0x0278, 3, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 0378-037A - PARALLEL PRINTER PORT (usually LPT2, sometimes LPT3) */
> -	r = ioport__register(kvm, 0x0378, &dummy_read_write_ioport_ops, 3, NULL);
> +	r = kvm__register_pio(kvm, 0x0378, 3, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
> -	r = ioport__register(kvm, 0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, 0x03d4, 1, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
> -	r = ioport__register(kvm, 0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, 0x03d5, 1, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
> -	r = ioport__register(kvm, 0x402, &seabios_debug_ops, 1, NULL);
> +	r = kvm__register_pio(kvm, 0x0402, 1, seabios_debug_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
>  	/* 0510 - QEMU BIOS configuration register */
> -	r = ioport__register(kvm, 0x510, &dummy_read_write_ioport_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, 0x0510, 2, dummy_mmio, NULL);
>  	if (r < 0)
>  		return r;
>  
> @@ -176,22 +124,21 @@ dev_base_init(ioport__setup_arch);
>  
>  static int ioport__remove_arch(struct kvm *kvm)
>  {
> -	ioport__unregister(kvm, 0x510);
> -	ioport__unregister(kvm, 0x402);
> -	ioport__unregister(kvm, 0x03D5);
> -	ioport__unregister(kvm, 0x03D4);
> -	ioport__unregister(kvm, 0x0378);
> -	ioport__unregister(kvm, 0x0278);
> -	ioport__unregister(kvm, 0x00F0);
> -	ioport__unregister(kvm, 0x00ED);
> -	ioport__unregister(kvm, IOPORT_DBG);
> -	ioport__unregister(kvm, 0x00C0);
> -	ioport__unregister(kvm, 0x00A0);
> -	ioport__unregister(kvm, 0x0092);
> -	ioport__unregister(kvm, 0x0040);
> -	ioport__unregister(kvm, 0x0020);
> -	ioport__unregister(kvm, 0x0000);
> -
> +	kvm__deregister_pio(kvm, 0x510);
> +	kvm__deregister_pio(kvm, 0x402);
> +	kvm__deregister_pio(kvm, 0x3d5);
> +	kvm__deregister_pio(kvm, 0x3d4);
> +	kvm__deregister_pio(kvm, 0x378);
> +	kvm__deregister_pio(kvm, 0x278);
> +	kvm__deregister_pio(kvm, 0x0f0);
> +	kvm__deregister_pio(kvm, 0x0ed);
> +	kvm__deregister_pio(kvm, IOPORT_DBG);
> +	kvm__deregister_pio(kvm, 0x0c0);
> +	kvm__deregister_pio(kvm, 0x0a0);
> +	kvm__deregister_pio(kvm, 0x092);
> +	kvm__deregister_pio(kvm, 0x040);
> +	kvm__deregister_pio(kvm, 0x020);
> +	kvm__deregister_pio(kvm, 0x000);
>  	return 0;
>  }
>  dev_base_exit(ioport__remove_arch);

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

* Re: [PATCH kvmtool 10/21] hw/rtc: Refactor trap handlers
  2020-12-10 14:28 ` [PATCH kvmtool 10/21] hw/rtc: Refactor " Andre Przywara
@ 2021-02-12 11:56   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 11:56 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide emulation functions compatible with the MMIO prototype.
>
> Merge the two different trap handlers into one function, checking for
> read/write and data/index register inside.
> Adjust the trap handlers to use that new function, and provide shims to
> implement the old ioport interface, for now.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/rtc.c | 70 ++++++++++++++++++++++++++++----------------------------
>  1 file changed, 35 insertions(+), 35 deletions(-)
>
> diff --git a/hw/rtc.c b/hw/rtc.c
> index 5483879f..664d4cb0 100644
> --- a/hw/rtc.c
> +++ b/hw/rtc.c
> @@ -42,11 +42,37 @@ static inline unsigned char bin2bcd(unsigned val)
>  	return ((val / 10) << 4) + val % 10;
>  }
>  
> -static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +			u32 len, u8 is_write, void *ptr)
>  {
>  	struct tm *tm;
>  	time_t ti;
>  
> +	if (is_write) {
> +		if (addr == 0x70) {	/* index register */
> +			u8 value = ioport__read8(data);
> +
> +			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
> +			rtc.cmos_idx		= value & ~(1UL << 7);
> +
> +			return;
> +		}
> +
> +		switch (rtc.cmos_idx) {
> +		case RTC_REG_C:
> +		case RTC_REG_D:
> +			/* Read-only */
> +			break;
> +		default:
> +			rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
> +			break;
> +		}
> +		return;
> +	}
> +
> +	if (addr == 0x70)
> +		return;
> +
>  	time(&ti);
>  
>  	tm = gmtime(&ti);
> @@ -92,42 +118,23 @@ static bool cmos_ram_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 po
>  		ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
>  		break;
>  	}
> -
> -	return true;
>  }
>  
> -static bool cmos_ram_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static bool cmos_ram_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> -	switch (rtc.cmos_idx) {
> -	case RTC_REG_C:
> -	case RTC_REG_D:
> -		/* Read-only */
> -		break;
> -	default:
> -		rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
> -		break;
> -	}
> -
> +	cmos_ram_io(vcpu, port, data, size, false, NULL);
>  	return true;
>  }
>  
> -static struct ioport_operations cmos_ram_data_ioport_ops = {
> -	.io_out		= cmos_ram_data_out,
> -	.io_in		= cmos_ram_data_in,
> -};
> -
> -static bool cmos_ram_index_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static bool cmos_ram_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>  {
> -	u8 value = ioport__read8(data);
> -
> -	vcpu->kvm->nmi_disabled	= value & (1UL << 7);
> -	rtc.cmos_idx		= value & ~(1UL << 7);
> -
> +	cmos_ram_io(vcpu, port, data, size, true, NULL);
>  	return true;
>  }
>  
> -static struct ioport_operations cmos_ram_index_ioport_ops = {
> -	.io_out		= cmos_ram_index_out,
> +static struct ioport_operations cmos_ram_ioport_ops = {
> +	.io_out		= cmos_ram_out,
> +	.io_in		= cmos_ram_in,
>  };
>  
>  #ifdef CONFIG_HAS_LIBFDT
> @@ -162,21 +169,15 @@ int rtc__init(struct kvm *kvm)
>  		return r;
>  
>  	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> -	r = ioport__register(kvm, 0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
> +	r = ioport__register(kvm, 0x0070, &cmos_ram_ioport_ops, 2, NULL);
>  	if (r < 0)
>  		goto out_device;
>  
> -	r = ioport__register(kvm, 0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
> -	if (r < 0)
> -		goto out_ioport;
> -
>  	/* Set the VRT bit in Register D to indicate valid RAM and time */
>  	rtc.cmos_data[RTC_REG_D] = RTC_REG_D_VRT;
>  
>  	return r;
>  
> -out_ioport:
> -	ioport__unregister(kvm, 0x0070);
>  out_device:
>  	device__unregister(&rtc_dev_hdr);
>  
> @@ -188,7 +189,6 @@ int rtc__exit(struct kvm *kvm)
>  {
>  	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
>  	ioport__unregister(kvm, 0x0070);
> -	ioport__unregister(kvm, 0x0071);
>  
>  	return 0;
>  }

The behaviour is preserved with this patch, and it compiles, so:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,
Alex

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

* Re: [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler
  2020-12-10 14:28 ` [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler Andre Przywara
@ 2021-02-12 12:02   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 12:02 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> Now that the RTC device has a trap handler adhering to the MMIO fault
> handler prototype, let's switch over to the joint registration routine.
>
> This allows us to get rid of the ioport shim routines.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/rtc.c | 21 ++-------------------
>  1 file changed, 2 insertions(+), 19 deletions(-)
>
> diff --git a/hw/rtc.c b/hw/rtc.c
> index 664d4cb0..ee4c9102 100644
> --- a/hw/rtc.c
> +++ b/hw/rtc.c
> @@ -120,23 +120,6 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>  	}
>  }
>  
> -static bool cmos_ram_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	cmos_ram_io(vcpu, port, data, size, false, NULL);
> -	return true;
> -}
> -
> -static bool cmos_ram_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	cmos_ram_io(vcpu, port, data, size, true, NULL);
> -	return true;
> -}
> -
> -static struct ioport_operations cmos_ram_ioport_ops = {
> -	.io_out		= cmos_ram_out,
> -	.io_in		= cmos_ram_in,
> -};
> -
>  #ifdef CONFIG_HAS_LIBFDT
>  static void generate_rtc_fdt_node(void *fdt,
>  				  struct device_header *dev_hdr,
> @@ -169,7 +152,7 @@ int rtc__init(struct kvm *kvm)
>  		return r;
>  
>  	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> -	r = ioport__register(kvm, 0x0070, &cmos_ram_ioport_ops, 2, NULL);
> +	r = kvm__register_pio(kvm, 0x0070, 2, cmos_ram_io, NULL);
>  	if (r < 0)
>  		goto out_device;
>  
> @@ -188,7 +171,7 @@ dev_init(rtc__init);
>  int rtc__exit(struct kvm *kvm)
>  {
>  	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> -	ioport__unregister(kvm, 0x0070);
> +	kvm__deregister_pio(kvm, 0x0070);
>  
>  	return 0;
>  }

Looks good:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,
Alex

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

* Re: [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler
  2020-12-10 14:28 ` [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler Andre Przywara
@ 2021-02-12 17:50   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-12 17:50 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:28 PM, Andre Przywara wrote:
> To be able to use the VESA device with the new generic I/O trap handler,
> we need to use the different MMIO handler callback routine.
>
> Replace the existing dummy in and out handlers with a joint dummy
> MMIO handler, and register this using the new registration function.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/vesa.c | 19 +++++--------------
>  1 file changed, 5 insertions(+), 14 deletions(-)
>
> diff --git a/hw/vesa.c b/hw/vesa.c
> index 8659a002..7f82cdb4 100644
> --- a/hw/vesa.c
> +++ b/hw/vesa.c
> @@ -43,21 +43,11 @@ static struct framebuffer vesafb = {
>  	.mem_size	= VESA_MEM_SIZE,
>  };
>  
> -static bool vesa_pci_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void vesa_pci_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +		        u8 is_write, void *ptr)
>  {
> -	return true;
>  }
>  
> -static bool vesa_pci_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	return true;
> -}
> -
> -static struct ioport_operations vesa_io_ops = {
> -	.io_in			= vesa_pci_io_in,
> -	.io_out			= vesa_pci_io_out,
> -};
> -
>  static int vesa__bar_activate(struct kvm *kvm, struct pci_device_header *pci_hdr,
>  			      int bar_num, void *data)
>  {
> @@ -82,7 +72,8 @@ struct framebuffer *vesa__init(struct kvm *kvm)
>  	BUILD_BUG_ON(VESA_MEM_SIZE < VESA_BPP/8 * VESA_WIDTH * VESA_HEIGHT);
>  
>  	vesa_base_addr = pci_get_io_port_block(PCI_IO_SIZE);
> -	r = ioport__register(kvm, vesa_base_addr, &vesa_io_ops, PCI_IO_SIZE, NULL);
> +	r = kvm__register_pio(kvm, vesa_base_addr, PCI_IO_SIZE, vesa_pci_io,
> +			      NULL);
>  	if (r < 0)
>  		goto out_error;
>  
> @@ -116,7 +107,7 @@ unmap_dev:
>  unregister_device:
>  	device__unregister(&vesa_device);
>  unregister_ioport:
> -	ioport__unregister(kvm, vesa_base_addr);
> +	kvm__deregister_pio(kvm, vesa_base_addr);
>  out_error:
>  	return ERR_PTR(r);
>  }

Looks good:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex


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

* Re: [PATCH kvmtool 13/21] hw/serial: Refactor trap handler
  2020-12-10 14:29 ` [PATCH kvmtool 13/21] hw/serial: Refactor trap handler Andre Przywara
@ 2021-02-16 14:22   ` Alexandru Elisei
  2021-02-18 14:41     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-16 14:22 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

Patch looks good, nitpicks below.

On 12/10/20 2:29 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide an emulation function compatible with the MMIO prototype.
>
> Adjust the trap handler to use that new function, and provide shims to
> implement the old ioport interface, for now.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/serial.c | 97 +++++++++++++++++++++++++++++++++++------------------
>  1 file changed, 65 insertions(+), 32 deletions(-)
>
> diff --git a/hw/serial.c b/hw/serial.c
> index b0465d99..2907089c 100644
> --- a/hw/serial.c
> +++ b/hw/serial.c
> @@ -242,36 +242,31 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
>  	sysrq_pending = sysrq;
>  }
>  
> -static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
> -			   void *data, int size)
> +static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> +			   u16 offset, u8 data)
>  {
> -	struct serial8250_device *dev = ioport->priv;
> -	u16 offset;
>  	bool ret = true;
> -	char *addr = data;
>  
>  	mutex_lock(&dev->mutex);
>  
> -	offset = port - dev->iobase;
> -
>  	switch (offset) {
>  	case UART_TX:
>  		if (dev->lcr & UART_LCR_DLAB) {
> -			dev->dll = ioport__read8(data);
> +			dev->dll = data;
>  			break;
>  		}
>  
>  		/* Loopback mode */
>  		if (dev->mcr & UART_MCR_LOOP) {
>  			if (dev->rxcnt < FIFO_LEN) {
> -				dev->rxbuf[dev->rxcnt++] = *addr;
> +				dev->rxbuf[dev->rxcnt++] = data;
>  				dev->lsr |= UART_LSR_DR;
>  			}
>  			break;
>  		}
>  
>  		if (dev->txcnt < FIFO_LEN) {
> -			dev->txbuf[dev->txcnt++] = *addr;
> +			dev->txbuf[dev->txcnt++] = data;
>  			dev->lsr &= ~UART_LSR_TEMT;
>  			if (dev->txcnt == FIFO_LEN / 2)
>  				dev->lsr &= ~UART_LSR_THRE;
> @@ -283,18 +278,18 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
>  		break;
>  	case UART_IER:
>  		if (!(dev->lcr & UART_LCR_DLAB))
> -			dev->ier = ioport__read8(data) & 0x0f;
> +			dev->ier = data & 0x0f;
>  		else
> -			dev->dlm = ioport__read8(data);
> +			dev->dlm = data;
>  		break;
>  	case UART_FCR:
> -		dev->fcr = ioport__read8(data);
> +		dev->fcr = data;
>  		break;
>  	case UART_LCR:
> -		dev->lcr = ioport__read8(data);
> +		dev->lcr = data;
>  		break;
>  	case UART_MCR:
> -		dev->mcr = ioport__read8(data);
> +		dev->mcr = data;
>  		break;
>  	case UART_LSR:
>  		/* Factory test */
> @@ -303,7 +298,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
>  		/* Not used */
>  		break;
>  	case UART_SCR:
> -		dev->scr = ioport__read8(data);
> +		dev->scr = data;
>  		break;
>  	default:
>  		ret = false;
> @@ -336,46 +331,43 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
>  	}
>  }
>  
> -static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> +			  u16 offset, u8 *data)
>  {
> -	struct serial8250_device *dev = ioport->priv;
> -	u16 offset;
>  	bool ret = true;
>  
>  	mutex_lock(&dev->mutex);
>  
> -	offset = port - dev->iobase;
> -
>  	switch (offset) {
>  	case UART_RX:
>  		if (dev->lcr & UART_LCR_DLAB)
> -			ioport__write8(data, dev->dll);
> +			*data = dev->dll;
>  		else
>  			serial8250_rx(dev, data);
>  		break;
>  	case UART_IER:
>  		if (dev->lcr & UART_LCR_DLAB)
> -			ioport__write8(data, dev->dlm);
> +			*data = dev->dlm;
>  		else
> -			ioport__write8(data, dev->ier);
> +			*data = dev->ier;
>  		break;
>  	case UART_IIR:
> -		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
> +		*data = dev->iir | UART_IIR_TYPE_BITS;
>  		break;
>  	case UART_LCR:
> -		ioport__write8(data, dev->lcr);
> +		*data = dev->lcr;
>  		break;
>  	case UART_MCR:
> -		ioport__write8(data, dev->mcr);
> +		*data = dev->mcr;
>  		break;
>  	case UART_LSR:
> -		ioport__write8(data, dev->lsr);
> +		*data = dev->lsr;
>  		break;
>  	case UART_MSR:
> -		ioport__write8(data, dev->msr);
> +		*data = dev->msr;
>  		break;
>  	case UART_SCR:
> -		ioport__write8(data, dev->scr);
> +		*data = dev->scr;
>  		break;
>  	default:
>  		ret = false;
> @@ -389,6 +381,47 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
>  	return ret;
>  }
>  
> +static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +			    u8 is_write, void *ptr)
> +{
> +	struct serial8250_device *dev = ptr;
> +	u8 value = 0;
> +
> +	if (is_write) {
> +		 value = *data;

Extra space before value.

> +
> +		serial8250_out(dev, vcpu, addr - dev->iobase, value);
> +	} else {
> +		if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
> +			*data = value;
> +	}
> +}
> +
> +static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> +				  u16 port, void *data, int size)
> +{
> +	struct serial8250_device *dev = ioport->priv;
> +	u8 value = ioport__read8(data);
> +
> +	serial8250_mmio(vcpu, port, &value, 1, true, dev);
> +
> +	return true;
> +}
> +
> +static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> +				 u16 port, void *data, int size)
> +{
> +	struct serial8250_device *dev = ioport->priv;
> +	u8 value = 0;
> +
> +
> +	serial8250_mmio(vcpu, port, &value, 1, false, dev);
> +
> +	ioport__write8(data, value);

This is correct, but confusing. You pass the address of a local variable as *data
to serial8250_mmio, serial8250_mmio conditionally updates the value at data (which
is &value from here), and then here we update the *data unconditionally. Why not
pass data directly to serial8250_mmio and skip the local variable? Am I missing
something?

Thanks,

Alex

> +
> +	return true;
> +}
> +
>  #ifdef CONFIG_HAS_LIBFDT
>  
>  char *fdt_stdout_path = NULL;
> @@ -427,8 +460,8 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
>  #endif
>  
>  static struct ioport_operations serial8250_ops = {
> -	.io_in			= serial8250_in,
> -	.io_out			= serial8250_out,
> +	.io_in			= serial8250_ioport_in,
> +	.io_out			= serial8250_ioport_out,
>  };
>  
>  static int serial8250__device_init(struct kvm *kvm,

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

* Re: [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers
  2020-12-10 14:29 ` [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers Andre Przywara
@ 2021-02-16 14:31   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-16 14:31 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

Looks correct to me:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

On 12/10/20 2:29 PM, Andre Przywara wrote:
> Now that the serial device has a trap handler adhering to the MMIO fault
> handler prototype, let's switch over to the joint registration routine.
>
> This allows us to get rid of the ioport shim routines.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/serial.c | 36 +++---------------------------------
>  1 file changed, 3 insertions(+), 33 deletions(-)
>
> diff --git a/hw/serial.c b/hw/serial.c
> index 2907089c..d840eebc 100644
> --- a/hw/serial.c
> +++ b/hw/serial.c
> @@ -397,31 +397,6 @@ static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  	}
>  }
>  
> -static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> -				  u16 port, void *data, int size)
> -{
> -	struct serial8250_device *dev = ioport->priv;
> -	u8 value = ioport__read8(data);
> -
> -	serial8250_mmio(vcpu, port, &value, 1, true, dev);
> -
> -	return true;
> -}
> -
> -static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> -				 u16 port, void *data, int size)
> -{
> -	struct serial8250_device *dev = ioport->priv;
> -	u8 value = 0;
> -
> -
> -	serial8250_mmio(vcpu, port, &value, 1, false, dev);
> -
> -	ioport__write8(data, value);
> -
> -	return true;
> -}
> -
>  #ifdef CONFIG_HAS_LIBFDT
>  
>  char *fdt_stdout_path = NULL;
> @@ -459,11 +434,6 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
>  }
>  #endif
>  
> -static struct ioport_operations serial8250_ops = {
> -	.io_in			= serial8250_ioport_in,
> -	.io_out			= serial8250_ioport_out,
> -};
> -
>  static int serial8250__device_init(struct kvm *kvm,
>  				   struct serial8250_device *dev)
>  {
> @@ -474,7 +444,7 @@ static int serial8250__device_init(struct kvm *kvm,
>  		return r;
>  
>  	ioport__map_irq(&dev->irq);
> -	r = ioport__register(kvm, dev->iobase, &serial8250_ops, 8, dev);
> +	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
>  
>  	return r;
>  }
> @@ -497,7 +467,7 @@ cleanup:
>  	for (j = 0; j <= i; j++) {
>  		struct serial8250_device *dev = &devices[j];
>  
> -		ioport__unregister(kvm, dev->iobase);
> +		kvm__deregister_pio(kvm, dev->iobase);
>  		device__unregister(&dev->dev_hdr);
>  	}
>  
> @@ -513,7 +483,7 @@ int serial8250__exit(struct kvm *kvm)
>  	for (i = 0; i < ARRAY_SIZE(devices); i++) {
>  		struct serial8250_device *dev = &devices[i];
>  
> -		r = ioport__unregister(kvm, dev->iobase);
> +		r = kvm__deregister_pio(kvm, dev->iobase);
>  		if (r < 0)
>  			return r;
>  		device__unregister(&dev->dev_hdr);

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

* Re: [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler
  2020-12-10 14:29 ` [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler Andre Przywara
@ 2021-02-16 14:47   ` Alexandru Elisei
  2021-02-18 15:51     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-16 14:47 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

Looks good, one nitpick below.

On 12/10/20 2:29 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide an emulation function compatible with the MMIO prototype.
>
> Adjust the I/O port trap handler to use that new function, and provide
> shims to implement the old ioport interface, for now.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  vfio/core.c | 51 ++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 36 insertions(+), 15 deletions(-)
>
> diff --git a/vfio/core.c b/vfio/core.c
> index 0b45e78b..f55f1f87 100644
> --- a/vfio/core.c
> +++ b/vfio/core.c
> @@ -81,15 +81,12 @@ out_free_buf:
>  	return ret;
>  }
>  
> -static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> -			   u16 port, void *data, int len)
> +static bool _vfio_ioport_in(struct vfio_region *region, u32 offset,
> +			    void *data, int len)
>  {
> -	u32 val;
> -	ssize_t nr;
> -	struct vfio_region *region = ioport->priv;
>  	struct vfio_device *vdev = region->vdev;
> -
> -	u32 offset = port - region->port_base;
> +	ssize_t nr;
> +	u32 val;
>  
>  	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_READ))
>  		return false;
> @@ -97,7 +94,7 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
>  	nr = pread(vdev->fd, &val, len, region->info.offset + offset);
>  	if (nr != len) {
>  		vfio_dev_err(vdev, "could not read %d bytes from I/O port 0x%x\n",
> -			     len, port);
> +			     len, offset);

To keep things functionally identical, shouldn't that be offset +
region->port_base? I think it's easier to identify the device when we have the PCI
ioport address.

Thanks,

Alex

>  		return false;
>  	}
>  
> @@ -118,15 +115,13 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
>  	return true;
>  }
>  
> -static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> -			    u16 port, void *data, int len)
> +static bool _vfio_ioport_out(struct vfio_region *region, u32 offset,
> +			     void *data, int len)
>  {
> -	u32 val;
> -	ssize_t nr;
> -	struct vfio_region *region = ioport->priv;
>  	struct vfio_device *vdev = region->vdev;
> +	ssize_t nr;
> +	u32 val;
>  
> -	u32 offset = port - region->port_base;
>  
>  	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_WRITE))
>  		return false;
> @@ -148,11 +143,37 @@ static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
>  	nr = pwrite(vdev->fd, &val, len, region->info.offset + offset);
>  	if (nr != len)
>  		vfio_dev_err(vdev, "could not write %d bytes to I/O port 0x%x",
> -			     len, port);
> +			     len, offset);
>  
>  	return nr == len;
>  }
>  
> +static void vfio_ioport_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> +			     u8 is_write, void *ptr)
> +{
> +	struct vfio_region *region = ptr;
> +	u32 offset = addr - region->port_base;
> +
> +	if (is_write)
> +		_vfio_ioport_out(region, offset, data, len);
> +	else
> +		_vfio_ioport_in(region, offset, data, len);
> +}
> +
> +static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> +			    u16 port, void *data, int len)
> +{
> +	vfio_ioport_mmio(vcpu, port, data, len, true, ioport->priv);
> +	return true;
> +}
> +
> +static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> +			   u16 port, void *data, int len)
> +{
> +	vfio_ioport_mmio(vcpu, port, data, len, false, ioport->priv);
> +	return true;
> +}
> +
>  static struct ioport_operations vfio_ioport_ops = {
>  	.io_in	= vfio_ioport_in,
>  	.io_out	= vfio_ioport_out,

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

* Re: [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers
  2020-12-10 14:29 ` [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers Andre Przywara
@ 2021-02-16 14:52   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-16 14:52 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

Looks good, _vfio_ioport_{in,out} could have been renamed to vfio_ioport_{in,out},
but it's fine either way:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

On 12/10/20 2:29 PM, Andre Przywara wrote:
> Now that the vfio device has a trap handler adhering to the MMIO fault
> handler prototype, let's switch over to the joint registration routine.
>
> This allows us to get rid of the ioport shim routines.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  vfio/core.c | 29 ++++++-----------------------
>  1 file changed, 6 insertions(+), 23 deletions(-)
>
> diff --git a/vfio/core.c b/vfio/core.c
> index f55f1f87..10919101 100644
> --- a/vfio/core.c
> +++ b/vfio/core.c
> @@ -160,25 +160,6 @@ static void vfio_ioport_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  		_vfio_ioport_in(region, offset, data, len);
>  }
>  
> -static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> -			    u16 port, void *data, int len)
> -{
> -	vfio_ioport_mmio(vcpu, port, data, len, true, ioport->priv);
> -	return true;
> -}
> -
> -static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> -			   u16 port, void *data, int len)
> -{
> -	vfio_ioport_mmio(vcpu, port, data, len, false, ioport->priv);
> -	return true;
> -}
> -
> -static struct ioport_operations vfio_ioport_ops = {
> -	.io_in	= vfio_ioport_in,
> -	.io_out	= vfio_ioport_out,
> -};
> -
>  static void vfio_mmio_access(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>  			     u8 is_write, void *ptr)
>  {
> @@ -223,9 +204,11 @@ static int vfio_setup_trap_region(struct kvm *kvm, struct vfio_device *vdev,
>  				  struct vfio_region *region)
>  {
>  	if (region->is_ioport) {
> -		int port = ioport__register(kvm, region->port_base,
> -					   &vfio_ioport_ops, region->info.size,
> -					   region);
> +		int port;
> +
> +		port = kvm__register_pio(kvm, region->port_base,
> +					 region->info.size, vfio_ioport_mmio,
> +					 region);
>  		if (port < 0)
>  			return port;
>  		return 0;
> @@ -292,7 +275,7 @@ void vfio_unmap_region(struct kvm *kvm, struct vfio_region *region)
>  		munmap(region->host_addr, region->info.size);
>  		region->host_addr = NULL;
>  	} else if (region->is_ioport) {
> -		ioport__unregister(kvm, region->port_base);
> +		kvm__deregister_pio(kvm, region->port_base);
>  	} else {
>  		kvm__deregister_mmio(kvm, region->guest_phys_addr);
>  	}

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

* Re: [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler
  2020-12-10 14:29 ` [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler Andre Przywara
@ 2021-02-16 17:03   ` Alexandru Elisei
  2021-02-18 16:13     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-16 17:03 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

Nitpick below, otherwise looks good.

On 12/10/20 2:29 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide an emulation function compatible with the MMIO prototype.
>
> Adjust the existing MMIO callback routine to automatically determine
> the region this trap came through, and call the existing I/O handlers.
> Register the ioport region using the new registration function.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  virtio/pci.c | 42 ++++++++++--------------------------------
>  1 file changed, 10 insertions(+), 32 deletions(-)
>
> diff --git a/virtio/pci.c b/virtio/pci.c
> index 6eea6c68..49d3f4d5 100644
> --- a/virtio/pci.c
> +++ b/virtio/pci.c
> @@ -178,15 +178,6 @@ static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev
>  	return ret;
>  }
>  
> -static bool virtio_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	struct virtio_device *vdev = ioport->priv;
> -	struct virtio_pci *vpci = vdev->virtio;
> -	unsigned long offset = port - virtio_pci__port_addr(vpci);
> -
> -	return virtio_pci__data_in(vcpu, vdev, offset, data, size);
> -}
> -
>  static void update_msix_map(struct virtio_pci *vpci,
>  			    struct msix_table *msix_entry, u32 vecnum)
>  {
> @@ -334,20 +325,6 @@ static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vde
>  	return ret;
>  }
>  
> -static bool virtio_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	struct virtio_device *vdev = ioport->priv;
> -	struct virtio_pci *vpci = vdev->virtio;
> -	unsigned long offset = port - virtio_pci__port_addr(vpci);
> -
> -	return virtio_pci__data_out(vcpu, vdev, offset, data, size);
> -}
> -
> -static struct ioport_operations virtio_pci__io_ops = {
> -	.io_in	= virtio_pci__io_in,
> -	.io_out	= virtio_pci__io_out,
> -};
> -
>  static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
>  					   u64 addr, u8 *data, u32 len,
>  					   u8 is_write, void *ptr)
> @@ -455,12 +432,15 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
>  {
>  	struct virtio_device *vdev = ptr;
>  	struct virtio_pci *vpci = vdev->virtio;
> -	u32 mmio_addr = virtio_pci__mmio_addr(vpci);
> +	u32 base_addr = virtio_pci__mmio_addr(vpci);
> +
> +	if (addr < base_addr || addr >= base_addr + PCI_IO_SIZE)
> +		base_addr = virtio_pci__port_addr(vpci);

There are only two BARs that use this callback, the ioport BAR (BAR0) and the
memory BAR (BAR1) (MSIX uses a different emulation callback). The condition above
says that if addr is not inside the region described by the memory BAR, then it's
an ioport BAR. How about checking explicitly that it is inside the ioport region
like this (compile tested only), which looks a bit more intuitive for me:

diff --git a/virtio/pci.c b/virtio/pci.c
index 49d3f4d524b2..4024bcd709cd 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -432,10 +432,15 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
 {
        struct virtio_device *vdev = ptr;
        struct virtio_pci *vpci = vdev->virtio;
-       u32 base_addr = virtio_pci__mmio_addr(vpci);
+       u32 mmio_addr = virtio_pci__mmio_addr(vpci);
+       u32 ioport_addr = virtio_pci__port_addr(vpci);
+       u32 base_addr;
 
-       if (addr < base_addr || addr >= base_addr + PCI_IO_SIZE)
-               base_addr = virtio_pci__port_addr(vpci);
+       if (addr >= ioport_addr &&
+           addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0))
+               base_addr = ioport_addr;
+       else
+               base_addr = mmio_addr;
 
        if (!is_write)
                virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);

Thanks,

Alex

>  
>  	if (!is_write)
> -		virtio_pci__data_in(vcpu, vdev, addr - mmio_addr, data, len);
> +		virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
>  	else
> -		virtio_pci__data_out(vcpu, vdev, addr - mmio_addr, data, len);
> +		virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len);
>  }
>  
>  static int virtio_pci__bar_activate(struct kvm *kvm,
> @@ -478,10 +458,8 @@ static int virtio_pci__bar_activate(struct kvm *kvm,
>  
>  	switch (bar_num) {
>  	case 0:
> -		r = ioport__register(kvm, bar_addr, &virtio_pci__io_ops,
> -				     bar_size, vdev);
> -		if (r > 0)
> -			r = 0;
> +		r = kvm__register_pio(kvm, bar_addr, bar_size,
> +				      virtio_pci__io_mmio_callback, vdev);
>  		break;
>  	case 1:
>  		r =  kvm__register_mmio(kvm, bar_addr, bar_size, false,
> @@ -510,7 +488,7 @@ static int virtio_pci__bar_deactivate(struct kvm *kvm,
>  
>  	switch (bar_num) {
>  	case 0:
> -		r = ioport__unregister(kvm, bar_addr);
> +		r = kvm__deregister_pio(kvm, bar_addr);
>  		break;
>  	case 1:
>  	case 2:
> @@ -625,7 +603,7 @@ int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
>  	virtio_pci__reset(kvm, vdev);
>  	kvm__deregister_mmio(kvm, virtio_pci__mmio_addr(vpci));
>  	kvm__deregister_mmio(kvm, virtio_pci__msix_io_addr(vpci));
> -	ioport__unregister(kvm, virtio_pci__port_addr(vpci));
> +	kvm__deregister_pio(kvm, virtio_pci__port_addr(vpci));
>  
>  	return 0;
>  }

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

* Re: [PATCH kvmtool 18/21] pci: Switch trap handling to use MMIO handler
  2020-12-10 14:29 ` [PATCH kvmtool 18/21] pci: " Andre Przywara
@ 2021-02-17 15:14   ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-17 15:14 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:29 PM, Andre Przywara wrote:
> With the planned retirement of the special ioport emulation code, we
> need to provide an emulation function compatible with the MMIO prototype.
>
> Merge the existing _in and _out handlers to adhere to that MMIO
> interface, and register these using the new registration function.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>

It looks like there's no change in functionality, the patch looks correct to me:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

> ---
>  pci.c | 82 +++++++++++++++++------------------------------------------
>  1 file changed, 24 insertions(+), 58 deletions(-)
>
> diff --git a/pci.c b/pci.c
> index 2e2c0270..d6da79e0 100644
> --- a/pci.c
> +++ b/pci.c
> @@ -87,29 +87,16 @@ static void *pci_config_address_ptr(u16 port)
>  	return base + offset;
>  }
>  
> -static bool pci_config_address_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void pci_config_address_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +				    u32 len, u8 is_write, void *ptr)
>  {
> -	void *p = pci_config_address_ptr(port);
> +	void *p = pci_config_address_ptr(addr);
>  
> -	memcpy(p, data, size);
> -
> -	return true;
> -}
> -
> -static bool pci_config_address_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	void *p = pci_config_address_ptr(port);
> -
> -	memcpy(data, p, size);
> -
> -	return true;
> +	if (is_write)
> +		memcpy(p, data, len);
> +	else
> +		memcpy(data, p, len);
>  }
> -
> -static struct ioport_operations pci_config_address_ops = {
> -	.io_in	= pci_config_address_in,
> -	.io_out	= pci_config_address_out,
> -};
> -
>  static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
>  {
>  	union pci_config_address pci_config_address;
> @@ -125,49 +112,27 @@ static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_numbe
>  	return !IS_ERR_OR_NULL(device__find_dev(DEVICE_BUS_PCI, device_number));
>  }
>  
> -static bool pci_config_data_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> -{
> -	union pci_config_address pci_config_address;
> -
> -	if (size > 4)
> -		size = 4;
> -
> -	pci_config_address.w = ioport__read32(&pci_config_address_bits);
> -	/*
> -	 * If someone accesses PCI configuration space offsets that are not
> -	 * aligned to 4 bytes, it uses ioports to signify that.
> -	 */
> -	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
> -
> -	pci__config_wr(vcpu->kvm, pci_config_address, data, size);
> -
> -	return true;
> -}
> -
> -static bool pci_config_data_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> +static void pci_config_data_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> +				 u32 len, u8 is_write, void *kvm)
>  {
>  	union pci_config_address pci_config_address;
>  
> -	if (size > 4)
> -		size = 4;
> +	if (len > 4)
> +		len = 4;
>  
>  	pci_config_address.w = ioport__read32(&pci_config_address_bits);
>  	/*
>  	 * If someone accesses PCI configuration space offsets that are not
>  	 * aligned to 4 bytes, it uses ioports to signify that.
>  	 */
> -	pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
> +	pci_config_address.reg_offset = addr - PCI_CONFIG_DATA;
>  
> -	pci__config_rd(vcpu->kvm, pci_config_address, data, size);
> -
> -	return true;
> +	if (is_write)
> +		pci__config_wr(vcpu->kvm, pci_config_address, data, len);
> +	else
> +		pci__config_rd(vcpu->kvm, pci_config_address, data, len);
>  }
>  
> -static struct ioport_operations pci_config_data_ops = {
> -	.io_in	= pci_config_data_in,
> -	.io_out	= pci_config_data_out,
> -};
> -
>  static int pci_activate_bar(struct kvm *kvm, struct pci_device_header *pci_hdr,
>  			    int bar_num)
>  {
> @@ -512,11 +477,12 @@ int pci__init(struct kvm *kvm)
>  {
>  	int r;
>  
> -	r = ioport__register(kvm, PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
> +	r = kvm__register_pio(kvm, PCI_CONFIG_DATA, 4,
> +				 pci_config_data_mmio, NULL);
>  	if (r < 0)
>  		return r;
> -
> -	r = ioport__register(kvm, PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
> +	r = kvm__register_pio(kvm, PCI_CONFIG_ADDRESS, 4,
> +				 pci_config_address_mmio, NULL);
>  	if (r < 0)
>  		goto err_unregister_data;
>  
> @@ -528,17 +494,17 @@ int pci__init(struct kvm *kvm)
>  	return 0;
>  
>  err_unregister_addr:
> -	ioport__unregister(kvm, PCI_CONFIG_ADDRESS);
> +	kvm__deregister_pio(kvm, PCI_CONFIG_ADDRESS);
>  err_unregister_data:
> -	ioport__unregister(kvm, PCI_CONFIG_DATA);
> +	kvm__deregister_pio(kvm, PCI_CONFIG_DATA);
>  	return r;
>  }
>  dev_base_init(pci__init);
>  
>  int pci__exit(struct kvm *kvm)
>  {
> -	ioport__unregister(kvm, PCI_CONFIG_DATA);
> -	ioport__unregister(kvm, PCI_CONFIG_ADDRESS);
> +	kvm__deregister_pio(kvm, PCI_CONFIG_DATA);
> +	kvm__deregister_pio(kvm, PCI_CONFIG_ADDRESS);
>  
>  	return 0;
>  }

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

* Re: [PATCH kvmtool 19/21] Remove ioport specific routines
  2020-12-10 14:29 ` [PATCH kvmtool 19/21] Remove ioport specific routines Andre Przywara
@ 2021-02-17 15:49   ` Alexandru Elisei
  2021-02-17 16:11     ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-17 15:49 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:29 PM, Andre Przywara wrote:
> Now that all users of the dedicated ioport trap handler interface are
> gone, we can retire the code associated with it.
>
> This removes ioport.c and ioport.h, along with removing prototypes from
> other header files.
>
> This also transfers the responsibility for port I/O trap handling
> entirely into the new routine in mmio.c.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  Makefile             |   1 -
>  include/kvm/ioport.h |  20 -----
>  include/kvm/kvm.h    |   2 -
>  ioport.c             | 173 -------------------------------------------
>  mmio.c               |   2 +-
>  5 files changed, 1 insertion(+), 197 deletions(-)
>  delete mode 100644 ioport.c
>
> diff --git a/Makefile b/Makefile
> index 35bb1182..94ff5da6 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -56,7 +56,6 @@ OBJS	+= framebuffer.o
>  OBJS	+= guest_compat.o
>  OBJS	+= hw/rtc.o
>  OBJS	+= hw/serial.o
> -OBJS	+= ioport.o
>  OBJS	+= irq.o
>  OBJS	+= kvm-cpu.o
>  OBJS	+= kvm.o
> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> index a61038e2..38636553 100644
> --- a/include/kvm/ioport.h
> +++ b/include/kvm/ioport.h
> @@ -17,28 +17,8 @@
>  
>  struct kvm;

Looks to me like the above forward declaration can be removed; same for all the
includes except linux/byteorder.h, needed for the lexx_to_cpu/cpu_to_lexx
functions, and linux/types.h for the uxx typedefs. Otherwise looks good.

Thanks,

Alex

>  
> -struct ioport {
> -	struct rb_int_node		node;
> -	struct ioport_operations	*ops;
> -	void				*priv;
> -	struct device_header		dev_hdr;
> -	u32				refcount;
> -	bool				remove;
> -};
> -
> -struct ioport_operations {
> -	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> -	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> -};
> -
>  void ioport__map_irq(u8 *irq);
>  
> -int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> -				  int count, void *param);
> -int ioport__unregister(struct kvm *kvm, u16 port);
> -int ioport__init(struct kvm *kvm);
> -int ioport__exit(struct kvm *kvm);
> -
>  static inline u8 ioport__read8(u8 *data)
>  {
>  	return *data;
> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> index 14f9d58b..e70f8ef6 100644
> --- a/include/kvm/kvm.h
> +++ b/include/kvm/kvm.h
> @@ -119,8 +119,6 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
>  void kvm__irq_trigger(struct kvm *kvm, int irq);
>  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
>  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> -		      int direction, int size, u32 count);
>  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
>  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
>  		      enum kvm_mem_type type);
> diff --git a/ioport.c b/ioport.c
> deleted file mode 100644
> index 204d8103..00000000
> --- a/ioport.c
> +++ /dev/null
> @@ -1,173 +0,0 @@
> -#include "kvm/ioport.h"
> -
> -#include "kvm/kvm.h"
> -#include "kvm/util.h"
> -#include "kvm/rbtree-interval.h"
> -#include "kvm/mutex.h"
> -
> -#include <linux/kvm.h>	/* for KVM_EXIT_* */
> -#include <linux/types.h>
> -
> -#include <stdbool.h>
> -#include <limits.h>
> -#include <stdlib.h>
> -#include <stdio.h>
> -
> -#define ioport_node(n) rb_entry(n, struct ioport, node)
> -
> -static DEFINE_MUTEX(ioport_lock);
> -
> -static struct rb_root		ioport_tree = RB_ROOT;
> -
> -static struct ioport *ioport_search(struct rb_root *root, u64 addr)
> -{
> -	struct rb_int_node *node;
> -
> -	node = rb_int_search_single(root, addr);
> -	if (node == NULL)
> -		return NULL;
> -
> -	return ioport_node(node);
> -}
> -
> -static int ioport_insert(struct rb_root *root, struct ioport *data)
> -{
> -	return rb_int_insert(root, &data->node);
> -}
> -
> -static void ioport_remove(struct rb_root *root, struct ioport *data)
> -{
> -	rb_int_erase(root, &data->node);
> -}
> -
> -static struct ioport *ioport_get(struct rb_root *root, u64 addr)
> -{
> -	struct ioport *ioport;
> -
> -	mutex_lock(&ioport_lock);
> -	ioport = ioport_search(root, addr);
> -	if (ioport)
> -		ioport->refcount++;
> -	mutex_unlock(&ioport_lock);
> -
> -	return ioport;
> -}
> -
> -/* Called with ioport_lock held. */
> -static void ioport_unregister(struct rb_root *root, struct ioport *data)
> -{
> -	ioport_remove(root, data);
> -	free(data);
> -}
> -
> -static void ioport_put(struct rb_root *root, struct ioport *data)
> -{
> -	mutex_lock(&ioport_lock);
> -	data->refcount--;
> -	if (data->remove && data->refcount == 0)
> -		ioport_unregister(root, data);
> -	mutex_unlock(&ioport_lock);
> -}
> -
> -int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
> -{
> -	struct ioport *entry;
> -	int r;
> -
> -	entry = malloc(sizeof(*entry));
> -	if (entry == NULL)
> -		return -ENOMEM;
> -
> -	*entry = (struct ioport) {
> -		.node		= RB_INT_INIT(port, port + count),
> -		.ops		= ops,
> -		.priv		= param,
> -		/*
> -		 * Start from 0 because ioport__unregister() doesn't decrement
> -		 * the reference count.
> -		 */
> -		.refcount	= 0,
> -		.remove		= false,
> -	};
> -
> -	mutex_lock(&ioport_lock);
> -	r = ioport_insert(&ioport_tree, entry);
> -	if (r < 0)
> -		goto out_free;
> -	mutex_unlock(&ioport_lock);
> -
> -	return port;
> -
> -out_free:
> -	free(entry);
> -	mutex_unlock(&ioport_lock);
> -	return r;
> -}
> -
> -int ioport__unregister(struct kvm *kvm, u16 port)
> -{
> -	struct ioport *entry;
> -
> -	mutex_lock(&ioport_lock);
> -	entry = ioport_search(&ioport_tree, port);
> -	if (!entry) {
> -		mutex_unlock(&ioport_lock);
> -		return -ENOENT;
> -	}
> -	/* The same reasoning from kvm__deregister_mmio() applies. */
> -	if (entry->refcount == 0)
> -		ioport_unregister(&ioport_tree, entry);
> -	else
> -		entry->remove = true;
> -	mutex_unlock(&ioport_lock);
> -
> -	return 0;
> -}
> -
> -static const char *to_direction(int direction)
> -{
> -	if (direction == KVM_EXIT_IO_IN)
> -		return "IN";
> -	else
> -		return "OUT";
> -}
> -
> -static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
> -{
> -	fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
> -}
> -
> -bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
> -{
> -	struct ioport_operations *ops;
> -	bool ret = false;
> -	struct ioport *entry;
> -	void *ptr = data;
> -	struct kvm *kvm = vcpu->kvm;
> -
> -	entry = ioport_get(&ioport_tree, port);
> -	if (!entry)
> -		return kvm__emulate_pio(vcpu, port, data, direction,
> -					size, count);
> -
> -	ops	= entry->ops;
> -
> -	while (count--) {
> -		if (direction == KVM_EXIT_IO_IN && ops->io_in)
> -				ret = ops->io_in(entry, vcpu, port, ptr, size);
> -		else if (direction == KVM_EXIT_IO_OUT && ops->io_out)
> -				ret = ops->io_out(entry, vcpu, port, ptr, size);
> -
> -		ptr += size;
> -	}
> -
> -	ioport_put(&ioport_tree, entry);
> -
> -	if (ret)
> -		return true;
> -
> -	if (kvm->cfg.ioport_debug)
> -		ioport_error(port, data, direction, size, count);
> -
> -	return !kvm->cfg.ioport_debug;
> -}
> diff --git a/mmio.c b/mmio.c
> index 4cce1901..5249af39 100644
> --- a/mmio.c
> +++ b/mmio.c
> @@ -206,7 +206,7 @@ out:
>  	return true;
>  }
>  
> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> +bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data,
>  		     int direction, int size, u32 count)
>  {
>  	struct mmio_mapping *mmio;

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

* Re: [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality
  2021-02-11 14:05   ` Alexandru Elisei
@ 2021-02-17 15:54     ` Andre Przywara
  2021-02-17 16:06       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-17 15:54 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 14:05:27 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > The ioport routines support a special way of registering FDT node
> > generator functions. There is no reason to have this separate from the
> > already existing way via the device header.
> >
> > Now that the only user of this special ioport variety has been
> > transferred, we can retire this code, to simplify ioport handling.  
> 
> One comment below, but otherwise very nice cleanup.
> 
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  include/kvm/ioport.h |  4 ----
> >  ioport.c             | 34 ----------------------------------
> >  2 files changed, 38 deletions(-)
> >
> > diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> > index d0213541..a61038e2 100644
> > --- a/include/kvm/ioport.h
> > +++ b/include/kvm/ioport.h
> > @@ -29,10 +29,6 @@ struct ioport {
> >  struct ioport_operations {
> >  	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> >  	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> > -	void (*generate_fdt_node)(struct ioport *ioport, void *fdt,
> > -				  void (*generate_irq_prop)(void *fdt,
> > -							    u8 irq,
> > -							    enum irq_type));
> >  };
> >  
> >  void ioport__map_irq(u8 *irq);
> > diff --git a/ioport.c b/ioport.c
> > index 667e8386..b98836d3 100644
> > --- a/ioport.c
> > +++ b/ioport.c
> > @@ -56,7 +56,6 @@ static struct ioport *ioport_get(struct rb_root *root, u64 addr)
> >  /* Called with ioport_lock held. */
> >  static void ioport_unregister(struct rb_root *root, struct ioport *data)
> >  {
> > -	device__unregister(&data->dev_hdr);
> >  	ioport_remove(root, data);
> >  	free(data);
> >  }
> > @@ -70,30 +69,6 @@ static void ioport_put(struct rb_root *root, struct ioport *data)
> >  	mutex_unlock(&ioport_lock);
> >  }
> >  
> > -#ifdef CONFIG_HAS_LIBFDT
> > -static void generate_ioport_fdt_node(void *fdt,
> > -				     struct device_header *dev_hdr,
> > -				     void (*generate_irq_prop)(void *fdt,
> > -							       u8 irq,
> > -							       enum irq_type))
> > -{
> > -	struct ioport *ioport = container_of(dev_hdr, struct ioport, dev_hdr);
> > -	struct ioport_operations *ops = ioport->ops;
> > -
> > -	if (ops->generate_fdt_node)
> > -		ops->generate_fdt_node(ioport, fdt, generate_irq_prop);
> > -}
> > -#else
> > -static void generate_ioport_fdt_node(void *fdt,
> > -				     struct device_header *dev_hdr,
> > -				     void (*generate_irq_prop)(void *fdt,
> > -							       u8 irq,
> > -							       enum irq_type))
> > -{
> > -	die("Unable to generate device tree nodes without libfdt\n");
> > -}
> > -#endif
> > -
> >  int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
> >  {
> >  	struct ioport *entry;
> > @@ -107,10 +82,6 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
> >  		.node		= RB_INT_INIT(port, port + count),
> >  		.ops		= ops,
> >  		.priv		= param,
> > -		.dev_hdr	= (struct device_header) {
> > -			.bus_type	= DEVICE_BUS_IOPORT,
> > -			.data		= generate_ioport_fdt_node,
> > -		},  
> 
> Since the dev_hdr field is not used anymore, maybe it could also be removed from
> struct ioport in include/kvm/ioport.h?

I could (seems to indeed still work without it), but this whole
structure will go away with a later patch, so I didn't bother so far.
That's why I am not sure it's useful to do this at this point then.

Cheers,
Andre

> >  		/*
> >  		 * Start from 0 because ioport__unregister() doesn't decrement
> >  		 * the reference count.
> > @@ -123,15 +94,10 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
> >  	r = ioport_insert(&ioport_tree, entry);
> >  	if (r < 0)
> >  		goto out_free;
> > -	r = device__register(&entry->dev_hdr);
> > -	if (r < 0)
> > -		goto out_remove;
> >  	mutex_unlock(&ioport_lock);
> >  
> >  	return port;
> >  
> > -out_remove:
> > -	ioport_remove(&ioport_tree, entry);
> >  out_free:
> >  	free(entry);
> >  	mutex_unlock(&ioport_lock);  


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

* Re: [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality
  2021-02-17 15:54     ` Andre Przywara
@ 2021-02-17 16:06       ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-17 16:06 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/17/21 3:54 PM, Andre Przywara wrote:
> On Thu, 11 Feb 2021 14:05:27 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
>> Hi Andre,
>>
>> On 12/10/20 2:28 PM, Andre Przywara wrote:
>>> The ioport routines support a special way of registering FDT node
>>> generator functions. There is no reason to have this separate from the
>>> already existing way via the device header.
>>>
>>> Now that the only user of this special ioport variety has been
>>> transferred, we can retire this code, to simplify ioport handling.  
>> One comment below, but otherwise very nice cleanup.
>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  include/kvm/ioport.h |  4 ----
>>>  ioport.c             | 34 ----------------------------------
>>>  2 files changed, 38 deletions(-)
>>>
>>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
>>> index d0213541..a61038e2 100644
>>> --- a/include/kvm/ioport.h
>>> +++ b/include/kvm/ioport.h
>>> @@ -29,10 +29,6 @@ struct ioport {
>>>  struct ioport_operations {
>>>  	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
>>>  	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
>>> -	void (*generate_fdt_node)(struct ioport *ioport, void *fdt,
>>> -				  void (*generate_irq_prop)(void *fdt,
>>> -							    u8 irq,
>>> -							    enum irq_type));
>>>  };
>>>  
>>>  void ioport__map_irq(u8 *irq);
>>> diff --git a/ioport.c b/ioport.c
>>> index 667e8386..b98836d3 100644
>>> --- a/ioport.c
>>> +++ b/ioport.c
>>> @@ -56,7 +56,6 @@ static struct ioport *ioport_get(struct rb_root *root, u64 addr)
>>>  /* Called with ioport_lock held. */
>>>  static void ioport_unregister(struct rb_root *root, struct ioport *data)
>>>  {
>>> -	device__unregister(&data->dev_hdr);
>>>  	ioport_remove(root, data);
>>>  	free(data);
>>>  }
>>> @@ -70,30 +69,6 @@ static void ioport_put(struct rb_root *root, struct ioport *data)
>>>  	mutex_unlock(&ioport_lock);
>>>  }
>>>  
>>> -#ifdef CONFIG_HAS_LIBFDT
>>> -static void generate_ioport_fdt_node(void *fdt,
>>> -				     struct device_header *dev_hdr,
>>> -				     void (*generate_irq_prop)(void *fdt,
>>> -							       u8 irq,
>>> -							       enum irq_type))
>>> -{
>>> -	struct ioport *ioport = container_of(dev_hdr, struct ioport, dev_hdr);
>>> -	struct ioport_operations *ops = ioport->ops;
>>> -
>>> -	if (ops->generate_fdt_node)
>>> -		ops->generate_fdt_node(ioport, fdt, generate_irq_prop);
>>> -}
>>> -#else
>>> -static void generate_ioport_fdt_node(void *fdt,
>>> -				     struct device_header *dev_hdr,
>>> -				     void (*generate_irq_prop)(void *fdt,
>>> -							       u8 irq,
>>> -							       enum irq_type))
>>> -{
>>> -	die("Unable to generate device tree nodes without libfdt\n");
>>> -}
>>> -#endif
>>> -
>>>  int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
>>>  {
>>>  	struct ioport *entry;
>>> @@ -107,10 +82,6 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
>>>  		.node		= RB_INT_INIT(port, port + count),
>>>  		.ops		= ops,
>>>  		.priv		= param,
>>> -		.dev_hdr	= (struct device_header) {
>>> -			.bus_type	= DEVICE_BUS_IOPORT,
>>> -			.data		= generate_ioport_fdt_node,
>>> -		},  
>> Since the dev_hdr field is not used anymore, maybe it could also be removed from
>> struct ioport in include/kvm/ioport.h?
> I could (seems to indeed still work without it), but this whole
> structure will go away with a later patch, so I didn't bother so far.
> That's why I am not sure it's useful to do this at this point then.

Yes, you're totally right, no need to fiddle too much with it now because it will
removed later:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

>
> Cheers,
> Andre
>
>>>  		/*
>>>  		 * Start from 0 because ioport__unregister() doesn't decrement
>>>  		 * the reference count.
>>> @@ -123,15 +94,10 @@ int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, i
>>>  	r = ioport_insert(&ioport_tree, entry);
>>>  	if (r < 0)
>>>  		goto out_free;
>>> -	r = device__register(&entry->dev_hdr);
>>> -	if (r < 0)
>>> -		goto out_remove;
>>>  	mutex_unlock(&ioport_lock);
>>>  
>>>  	return port;
>>>  
>>> -out_remove:
>>> -	ioport_remove(&ioport_tree, entry);
>>>  out_free:
>>>  	free(entry);
>>>  	mutex_unlock(&ioport_lock);  

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

* Re: [PATCH kvmtool 19/21] Remove ioport specific routines
  2021-02-17 15:49   ` Alexandru Elisei
@ 2021-02-17 16:11     ` Alexandru Elisei
  2021-02-18 16:34       ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-17 16:11 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: linux-arm-kernel, Marc Zyngier, kvmarm, kvm

Hi Andre,

On 2/17/21 3:49 PM, Alexandru Elisei wrote:
> Hi Andre,
>
> On 12/10/20 2:29 PM, Andre Przywara wrote:
>> Now that all users of the dedicated ioport trap handler interface are
>> gone, we can retire the code associated with it.
>>
>> This removes ioport.c and ioport.h, along with removing prototypes from
>> other header files.
>>
>> This also transfers the responsibility for port I/O trap handling
>> entirely into the new routine in mmio.c.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  Makefile             |   1 -
>>  include/kvm/ioport.h |  20 -----
>>  include/kvm/kvm.h    |   2 -
>>  ioport.c             | 173 -------------------------------------------
>>  mmio.c               |   2 +-
>>  5 files changed, 1 insertion(+), 197 deletions(-)
>>  delete mode 100644 ioport.c
>>
>> diff --git a/Makefile b/Makefile
>> index 35bb1182..94ff5da6 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -56,7 +56,6 @@ OBJS	+= framebuffer.o
>>  OBJS	+= guest_compat.o
>>  OBJS	+= hw/rtc.o
>>  OBJS	+= hw/serial.o
>> -OBJS	+= ioport.o
>>  OBJS	+= irq.o
>>  OBJS	+= kvm-cpu.o
>>  OBJS	+= kvm.o
>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
>> index a61038e2..38636553 100644
>> --- a/include/kvm/ioport.h
>> +++ b/include/kvm/ioport.h
>> @@ -17,28 +17,8 @@
>>  
>>  struct kvm;
> Looks to me like the above forward declaration can be removed; same for all the
> includes except linux/byteorder.h, needed for the lexx_to_cpu/cpu_to_lexx
> functions, and linux/types.h for the uxx typedefs. Otherwise looks good.

Actually, ignore the part about removing the includes, it opens a new can of worms
- byteorder.h doesn't include compiler.h where __always_inline is defined, and
various files where struct kvm_cpu is used don't include kvm-cpu.h (like pci.c,
hw/serial.c, etc). The header removal is not trivial and I think it should be part
of another cleanup patch.

Thanks,

Alex

>
> Thanks,
>
> Alex
>
>>  
>> -struct ioport {
>> -	struct rb_int_node		node;
>> -	struct ioport_operations	*ops;
>> -	void				*priv;
>> -	struct device_header		dev_hdr;
>> -	u32				refcount;
>> -	bool				remove;
>> -};
>> -
>> -struct ioport_operations {
>> -	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
>> -	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
>> -};
>> -
>>  void ioport__map_irq(u8 *irq);
>>  
>> -int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
>> -				  int count, void *param);
>> -int ioport__unregister(struct kvm *kvm, u16 port);
>> -int ioport__init(struct kvm *kvm);
>> -int ioport__exit(struct kvm *kvm);
>> -
>>  static inline u8 ioport__read8(u8 *data)
>>  {
>>  	return *data;
>> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
>> index 14f9d58b..e70f8ef6 100644
>> --- a/include/kvm/kvm.h
>> +++ b/include/kvm/kvm.h
>> @@ -119,8 +119,6 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
>>  void kvm__irq_trigger(struct kvm *kvm, int irq);
>>  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
>>  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
>> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
>> -		      int direction, int size, u32 count);
>>  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
>>  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
>>  		      enum kvm_mem_type type);
>> diff --git a/ioport.c b/ioport.c
>> deleted file mode 100644
>> index 204d8103..00000000
>> --- a/ioport.c
>> +++ /dev/null
>> @@ -1,173 +0,0 @@
>> -#include "kvm/ioport.h"
>> -
>> -#include "kvm/kvm.h"
>> -#include "kvm/util.h"
>> -#include "kvm/rbtree-interval.h"
>> -#include "kvm/mutex.h"
>> -
>> -#include <linux/kvm.h>	/* for KVM_EXIT_* */
>> -#include <linux/types.h>
>> -
>> -#include <stdbool.h>
>> -#include <limits.h>
>> -#include <stdlib.h>
>> -#include <stdio.h>
>> -
>> -#define ioport_node(n) rb_entry(n, struct ioport, node)
>> -
>> -static DEFINE_MUTEX(ioport_lock);
>> -
>> -static struct rb_root		ioport_tree = RB_ROOT;
>> -
>> -static struct ioport *ioport_search(struct rb_root *root, u64 addr)
>> -{
>> -	struct rb_int_node *node;
>> -
>> -	node = rb_int_search_single(root, addr);
>> -	if (node == NULL)
>> -		return NULL;
>> -
>> -	return ioport_node(node);
>> -}
>> -
>> -static int ioport_insert(struct rb_root *root, struct ioport *data)
>> -{
>> -	return rb_int_insert(root, &data->node);
>> -}
>> -
>> -static void ioport_remove(struct rb_root *root, struct ioport *data)
>> -{
>> -	rb_int_erase(root, &data->node);
>> -}
>> -
>> -static struct ioport *ioport_get(struct rb_root *root, u64 addr)
>> -{
>> -	struct ioport *ioport;
>> -
>> -	mutex_lock(&ioport_lock);
>> -	ioport = ioport_search(root, addr);
>> -	if (ioport)
>> -		ioport->refcount++;
>> -	mutex_unlock(&ioport_lock);
>> -
>> -	return ioport;
>> -}
>> -
>> -/* Called with ioport_lock held. */
>> -static void ioport_unregister(struct rb_root *root, struct ioport *data)
>> -{
>> -	ioport_remove(root, data);
>> -	free(data);
>> -}
>> -
>> -static void ioport_put(struct rb_root *root, struct ioport *data)
>> -{
>> -	mutex_lock(&ioport_lock);
>> -	data->refcount--;
>> -	if (data->remove && data->refcount == 0)
>> -		ioport_unregister(root, data);
>> -	mutex_unlock(&ioport_lock);
>> -}
>> -
>> -int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
>> -{
>> -	struct ioport *entry;
>> -	int r;
>> -
>> -	entry = malloc(sizeof(*entry));
>> -	if (entry == NULL)
>> -		return -ENOMEM;
>> -
>> -	*entry = (struct ioport) {
>> -		.node		= RB_INT_INIT(port, port + count),
>> -		.ops		= ops,
>> -		.priv		= param,
>> -		/*
>> -		 * Start from 0 because ioport__unregister() doesn't decrement
>> -		 * the reference count.
>> -		 */
>> -		.refcount	= 0,
>> -		.remove		= false,
>> -	};
>> -
>> -	mutex_lock(&ioport_lock);
>> -	r = ioport_insert(&ioport_tree, entry);
>> -	if (r < 0)
>> -		goto out_free;
>> -	mutex_unlock(&ioport_lock);
>> -
>> -	return port;
>> -
>> -out_free:
>> -	free(entry);
>> -	mutex_unlock(&ioport_lock);
>> -	return r;
>> -}
>> -
>> -int ioport__unregister(struct kvm *kvm, u16 port)
>> -{
>> -	struct ioport *entry;
>> -
>> -	mutex_lock(&ioport_lock);
>> -	entry = ioport_search(&ioport_tree, port);
>> -	if (!entry) {
>> -		mutex_unlock(&ioport_lock);
>> -		return -ENOENT;
>> -	}
>> -	/* The same reasoning from kvm__deregister_mmio() applies. */
>> -	if (entry->refcount == 0)
>> -		ioport_unregister(&ioport_tree, entry);
>> -	else
>> -		entry->remove = true;
>> -	mutex_unlock(&ioport_lock);
>> -
>> -	return 0;
>> -}
>> -
>> -static const char *to_direction(int direction)
>> -{
>> -	if (direction == KVM_EXIT_IO_IN)
>> -		return "IN";
>> -	else
>> -		return "OUT";
>> -}
>> -
>> -static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
>> -{
>> -	fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
>> -}
>> -
>> -bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
>> -{
>> -	struct ioport_operations *ops;
>> -	bool ret = false;
>> -	struct ioport *entry;
>> -	void *ptr = data;
>> -	struct kvm *kvm = vcpu->kvm;
>> -
>> -	entry = ioport_get(&ioport_tree, port);
>> -	if (!entry)
>> -		return kvm__emulate_pio(vcpu, port, data, direction,
>> -					size, count);
>> -
>> -	ops	= entry->ops;
>> -
>> -	while (count--) {
>> -		if (direction == KVM_EXIT_IO_IN && ops->io_in)
>> -				ret = ops->io_in(entry, vcpu, port, ptr, size);
>> -		else if (direction == KVM_EXIT_IO_OUT && ops->io_out)
>> -				ret = ops->io_out(entry, vcpu, port, ptr, size);
>> -
>> -		ptr += size;
>> -	}
>> -
>> -	ioport_put(&ioport_tree, entry);
>> -
>> -	if (ret)
>> -		return true;
>> -
>> -	if (kvm->cfg.ioport_debug)
>> -		ioport_error(port, data, direction, size, count);
>> -
>> -	return !kvm->cfg.ioport_debug;
>> -}
>> diff --git a/mmio.c b/mmio.c
>> index 4cce1901..5249af39 100644
>> --- a/mmio.c
>> +++ b/mmio.c
>> @@ -206,7 +206,7 @@ out:
>>  	return true;
>>  }
>>  
>> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
>> +bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data,
>>  		     int direction, int size, u32 count)
>>  {
>>  	struct mmio_mapping *mmio;
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2021-02-11 17:32       ` Alexandru Elisei
@ 2021-02-17 16:46         ` Andre Przywara
  2021-02-22 10:23           ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-17 16:46 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 17:32:01 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> On 2/11/21 5:16 PM, Andre Przywara wrote:
> > On Wed, 10 Feb 2021 17:44:59 +0000
> > Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> >
> > Hi Alex,
> >  
> >> On 12/10/20 2:28 PM, Andre Przywara wrote:  
> >>> Since x86 had a special need for registering tons of special I/O ports,
> >>> we had an ioport__setup_arch() callback, to allow each architecture
> >>> to do the same. As it turns out no one uses it beside x86, so we remove
> >>> that unnecessary abstraction.
> >>>
> >>> The generic function was registered via a device_base_init() call, so
> >>> we just do the same for the x86 specific function only, and can remove
> >>> the unneeded ioport__setup_arch().
> >>>
> >>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>> ---
> >>>  arm/ioport.c         |  5 -----
> >>>  include/kvm/ioport.h |  1 -
> >>>  ioport.c             | 28 ----------------------------
> >>>  mips/kvm.c           |  5 -----
> >>>  powerpc/ioport.c     |  6 ------
> >>>  x86/ioport.c         | 25 ++++++++++++++++++++++++-
> >>>  6 files changed, 24 insertions(+), 46 deletions(-)
> >>>
> >>> diff --git a/arm/ioport.c b/arm/ioport.c
> >>> index 2f0feb9a..24092c9d 100644
> >>> --- a/arm/ioport.c
> >>> +++ b/arm/ioport.c
> >>> @@ -1,11 +1,6 @@
> >>>  #include "kvm/ioport.h"
> >>>  #include "kvm/irq.h"
> >>>  
> >>> -int ioport__setup_arch(struct kvm *kvm)
> >>> -{
> >>> -	return 0;
> >>> -}
> >>> -
> >>>  void ioport__map_irq(u8 *irq)
> >>>  {
> >>>  	*irq = irq__alloc_line();
> >>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> >>> index 039633f7..d0213541 100644
> >>> --- a/include/kvm/ioport.h
> >>> +++ b/include/kvm/ioport.h
> >>> @@ -35,7 +35,6 @@ struct ioport_operations {
> >>>  							    enum irq_type));
> >>>  };
> >>>  
> >>> -int ioport__setup_arch(struct kvm *kvm);
> >>>  void ioport__map_irq(u8 *irq);
> >>>  
> >>>  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> >>> diff --git a/ioport.c b/ioport.c
> >>> index 844a832d..667e8386 100644
> >>> --- a/ioport.c
> >>> +++ b/ioport.c
> >>> @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
> >>>  	return 0;
> >>>  }
> >>>  
> >>> -static void ioport__unregister_all(void)
> >>> -{
> >>> -	struct ioport *entry;
> >>> -	struct rb_node *rb;
> >>> -	struct rb_int_node *rb_node;
> >>> -
> >>> -	rb = rb_first(&ioport_tree);
> >>> -	while (rb) {
> >>> -		rb_node = rb_int(rb);
> >>> -		entry = ioport_node(rb_node);
> >>> -		ioport_unregister(&ioport_tree, entry);
> >>> -		rb = rb_first(&ioport_tree);
> >>> -	}
> >>> -}    
> >> I get the impression this is a rebasing artifact. The commit message doesn't
> >> mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
> >> far as I can tell it's still needed because there are places other than
> >> ioport__setup_arch() from where ioport__register() is called.  
> > I agree that the commit message is a bit thin on this fact, but the
> > functionality of ioport__unregister_all() is now in
> > x86/ioport.c:ioport__remove_arch(). I think removing ioport__init()
> > without removing ioport__exit() as well would look very weird, if not
> > hackish.  
> 
> Not necessarily. ioport__unregister_all() removes the ioports added by
> x86/ioport.c::ioport__setup_arch(), *plus* ioports added by different devices,
> like serial, rtc, virtio-pci and vfio-pci (which are used by arm/arm64).

Right, indeed. Not that it really matters, since we are about to exit
anyway, but it looks indeed I need to move this to a generic teardown
method, or actually just keep that part here in this file.

Will give this a try.

Thanks!
Andre

> >
> > I can amend the commit message to mention this, or is there anything
> > else I missed?
> >
> > Cheers,
> > Andre
> >  
> >>> -
> >>>  static const char *to_direction(int direction)
> >>>  {
> >>>  	if (direction == KVM_EXIT_IO_IN)
> >>> @@ -220,16 +205,3 @@ out:
> >>>  
> >>>  	return !kvm->cfg.ioport_debug;
> >>>  }
> >>> -
> >>> -int ioport__init(struct kvm *kvm)
> >>> -{
> >>> -	return ioport__setup_arch(kvm);
> >>> -}
> >>> -dev_base_init(ioport__init);
> >>> -
> >>> -int ioport__exit(struct kvm *kvm)
> >>> -{
> >>> -	ioport__unregister_all();
> >>> -	return 0;
> >>> -}
> >>> -dev_base_exit(ioport__exit);
> >>> diff --git a/mips/kvm.c b/mips/kvm.c
> >>> index 26355930..e110e5d5 100644
> >>> --- a/mips/kvm.c
> >>> +++ b/mips/kvm.c
> >>> @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
> >>>  		die_perror("KVM_IRQ_LINE ioctl");
> >>>  }
> >>>  
> >>> -int ioport__setup_arch(struct kvm *kvm)
> >>> -{
> >>> -	return 0;
> >>> -}
> >>> -
> >>>  bool kvm__arch_cpu_supports_vm(void)
> >>>  {
> >>>  	return true;
> >>> diff --git a/powerpc/ioport.c b/powerpc/ioport.c
> >>> index 0c188b61..a5cff4ee 100644
> >>> --- a/powerpc/ioport.c
> >>> +++ b/powerpc/ioport.c
> >>> @@ -12,12 +12,6 @@
> >>>  
> >>>  #include <stdlib.h>
> >>>  
> >>> -int ioport__setup_arch(struct kvm *kvm)
> >>> -{
> >>> -	/* PPC has no legacy ioports to set up */
> >>> -	return 0;
> >>> -}
> >>> -
> >>>  void ioport__map_irq(u8 *irq)
> >>>  {
> >>>  }
> >>> diff --git a/x86/ioport.c b/x86/ioport.c
> >>> index 7ad7b8f3..8c5c7699 100644
> >>> --- a/x86/ioport.c
> >>> +++ b/x86/ioport.c
> >>> @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
> >>>  {
> >>>  }
> >>>  
> >>> -int ioport__setup_arch(struct kvm *kvm)
> >>> +static int ioport__setup_arch(struct kvm *kvm)
> >>>  {
> >>>  	int r;
> >>>  
> >>> @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
> >>>  
> >>>  	return 0;
> >>>  }
> >>> +dev_base_init(ioport__setup_arch);
> >>> +
> >>> +static int ioport__remove_arch(struct kvm *kvm)
> >>> +{
> >>> +	ioport__unregister(kvm, 0x510);
> >>> +	ioport__unregister(kvm, 0x402);
> >>> +	ioport__unregister(kvm, 0x03D5);
> >>> +	ioport__unregister(kvm, 0x03D4);
> >>> +	ioport__unregister(kvm, 0x0378);
> >>> +	ioport__unregister(kvm, 0x0278);
> >>> +	ioport__unregister(kvm, 0x00F0);
> >>> +	ioport__unregister(kvm, 0x00ED);
> >>> +	ioport__unregister(kvm, IOPORT_DBG);
> >>> +	ioport__unregister(kvm, 0x00C0);
> >>> +	ioport__unregister(kvm, 0x00A0);
> >>> +	ioport__unregister(kvm, 0x0092);
> >>> +	ioport__unregister(kvm, 0x0040);
> >>> +	ioport__unregister(kvm, 0x0020);
> >>> +	ioport__unregister(kvm, 0x0000);
> >>> +
> >>> +	return 0;
> >>> +}
> >>> +dev_base_exit(ioport__remove_arch);    


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

* Re: [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses
  2020-12-10 14:29 ` [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses Andre Przywara
@ 2021-02-17 16:48   ` Alexandru Elisei
  2021-02-18 12:18     ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-17 16:48 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:29 PM, Andre Przywara wrote:
> Using the UART devices at their legacy I/O addresses as set by IBM in
> 1981 was a kludge we used for simplicity on ARM platforms as well.
> However this imposes problems due to their missing alignment and overlap
> with the PCI I/O address space.
>
> Now that we can switch a device easily between using ioports and MMIO,
> let's move the UARTs out of the first 4K of memory on ARM platforms.
>
> That should be transparent for well behaved guests, since the change is
> naturally reflected in the device tree. Even "earlycon" keeps working,
> as the stdout-path property is adjusted automatically.
>
> People providing direct earlycon parameters via the command line need to
> adjust it to: "earlycon=uart,mmio,0x1000000".
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/serial.c | 52 ++++++++++++++++++++++++++++++++++++----------------
>  1 file changed, 36 insertions(+), 16 deletions(-)
>
> diff --git a/hw/serial.c b/hw/serial.c
> index d840eebc..00fb3aa8 100644
> --- a/hw/serial.c
> +++ b/hw/serial.c
> @@ -13,6 +13,24 @@
>  
>  #include <pthread.h>
>  
> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> +#define serial_iobase(nr)	(0x1000000 + (nr) * 0x1000)
> +#define serial_irq(nr)		(32 + (nr))
> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
> +#else
> +#define serial_iobase_0		0x3f8
> +#define serial_iobase_1		0x2f8
> +#define serial_iobase_2		0x3e8
> +#define serial_iobase_3		0x2e8
> +#define serial_irq_0		4
> +#define serial_irq_1		3
> +#define serial_irq_2		4
> +#define serial_irq_3		3

Nitpick: serial_iobase_* and serial_irq_* could be changed to have two leading
underscores, to stress the fact that they are helpers for serial_iobase() and
serial_irq() and are not meant to be used by themselves. But that's just personal
preference, otherwise the patch looks really nice and clean:

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks,

Alex

> +#define serial_iobase(nr)	serial_iobase_##nr
> +#define serial_irq(nr)		serial_irq_##nr
> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
> +#endif
> +
>  /*
>   * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
>   * expects that for autodetection.
> @@ -27,7 +45,7 @@ struct serial8250_device {
>  	struct mutex		mutex;
>  	u8			id;
>  
> -	u16			iobase;
> +	u32			iobase;
>  	u8			irq;
>  	u8			irq_state;
>  	int			txcnt;
> @@ -65,56 +83,56 @@ static struct serial8250_device devices[] = {
>  	/* ttyS0 */
>  	[0]	= {
>  		.dev_hdr = {
> -			.bus_type	= DEVICE_BUS_IOPORT,
> +			.bus_type	= SERIAL8250_BUS_TYPE,
>  			.data		= serial8250_generate_fdt_node,
>  		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 0,
> -		.iobase			= 0x3f8,
> -		.irq			= 4,
> +		.iobase			= serial_iobase(0),
> +		.irq			= serial_irq(0),
>  
>  		SERIAL_REGS_SETTING
>  	},
>  	/* ttyS1 */
>  	[1]	= {
>  		.dev_hdr = {
> -			.bus_type	= DEVICE_BUS_IOPORT,
> +			.bus_type	= SERIAL8250_BUS_TYPE,
>  			.data		= serial8250_generate_fdt_node,
>  		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 1,
> -		.iobase			= 0x2f8,
> -		.irq			= 3,
> +		.iobase			= serial_iobase(1),
> +		.irq			= serial_irq(1),
>  
>  		SERIAL_REGS_SETTING
>  	},
>  	/* ttyS2 */
>  	[2]	= {
>  		.dev_hdr = {
> -			.bus_type	= DEVICE_BUS_IOPORT,
> +			.bus_type	= SERIAL8250_BUS_TYPE,
>  			.data		= serial8250_generate_fdt_node,
>  		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 2,
> -		.iobase			= 0x3e8,
> -		.irq			= 4,
> +		.iobase			= serial_iobase(2),
> +		.irq			= serial_irq(2),
>  
>  		SERIAL_REGS_SETTING
>  	},
>  	/* ttyS3 */
>  	[3]	= {
>  		.dev_hdr = {
> -			.bus_type	= DEVICE_BUS_IOPORT,
> +			.bus_type	= SERIAL8250_BUS_TYPE,
>  			.data		= serial8250_generate_fdt_node,
>  		},
>  		.mutex			= MUTEX_INITIALIZER,
>  
>  		.id			= 3,
> -		.iobase			= 0x2e8,
> -		.irq			= 3,
> +		.iobase			= serial_iobase(3),
> +		.irq			= serial_irq(3),
>  
>  		SERIAL_REGS_SETTING
>  	},
> @@ -444,7 +462,8 @@ static int serial8250__device_init(struct kvm *kvm,
>  		return r;
>  
>  	ioport__map_irq(&dev->irq);
> -	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
> +	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
> +				 SERIAL8250_BUS_TYPE);
>  
>  	return r;
>  }
> @@ -467,7 +486,7 @@ cleanup:
>  	for (j = 0; j <= i; j++) {
>  		struct serial8250_device *dev = &devices[j];
>  
> -		kvm__deregister_pio(kvm, dev->iobase);
> +		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
>  		device__unregister(&dev->dev_hdr);
>  	}
>  
> @@ -483,7 +502,8 @@ int serial8250__exit(struct kvm *kvm)
>  	for (i = 0; i < ARRAY_SIZE(devices); i++) {
>  		struct serial8250_device *dev = &devices[i];
>  
> -		r = kvm__deregister_pio(kvm, dev->iobase);
> +		r = kvm__deregister_iotrap(kvm, dev->iobase,
> +					   SERIAL8250_BUS_TYPE);
>  		if (r < 0)
>  			return r;
>  		device__unregister(&dev->dev_hdr);

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

* Re: [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation
  2021-02-11 16:10   ` Alexandru Elisei
@ 2021-02-17 17:43     ` Andre Przywara
  2021-02-22 15:50       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-17 17:43 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 16:10:16 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > In their core functionality MMIO and I/O port traps are not really
> > different, yet we still have two totally separate code paths for
> > handling them. Devices need to decide on one conduit or need to provide
> > different handler functions for each of them.
> >
> > Extend the existing MMIO emulation to also cover ioport handlers.
> > This just adds another RB tree root for holding the I/O port handlers,
> > but otherwise uses the same tree population and lookup code.  
> 
> Maybe I'm missing something, but why two trees? Is it valid to have an overlap
> between IO port and MMIO emulation? Or was it done to make the removal of ioport
> emulation easier?

So I thought about it as well, but figured it's easier this way:
- x86 allows overlap, PIO is a totally separate address space from
  memory/MMIO. Early x86 CPUs had pins to indicate a PIO bus cycle, but
  using the same address and data pins otherwise. In practise there
  might be no overlap when it comes to *MMIO* traps vs PIO on x86
  (there is DRAM only at the lowest 64K of the IBM PC memory map),
  but not sure we should rely on this.
- For non-x86 this would indeed be non-overlapping, but this would need
  to be translated at init time then? And then we can't move those
  anymore, I guess? So I found it cleaner to keep this separate, and do
  the translation at trap time.
- As a consequence we would need to have a bit indicating the address
  space. I haven't actually tried this, but my understanding is that
  this would spoil the whole rb_tree functions, since they rely on a
  linear addressing scheme, and adding another bit there would be at
  least cumbersome?

At the end I decided to go for separate trees, as also this was less
change.

I agree that it would be nice to have one tree, from a design point of
view, but I am afraid that would require more changes.
If need be, I think we can always unify them later on, on top of this
series?

> If it's not valid to have that overlap, then I think having one tree for both
> would better. Struct mmio_mapping would have to be augmented with a flags field
> that holds the same flags given to kvm__register_iotrap to differentiate between
> the two slightly different emulations. Saving the IOTRAP_COALESCE flag would also
> make it trivial to call KVM_UNREGISTER_COALESCED_MMIO in kvm__deregister_iotrap,
> which we currently don't do.
> 
> > "ioport" or "mmio" just become a flag in the registration function.
> > Provide wrappers to not break existing users, and allow an easy
> > transition for the existing ioport handlers.
> >
> > This also means that ioport handlers now can use the same emulation
> > callback prototype as MMIO handlers, which means we have to migrate them
> > over. To allow a smooth transition, we hook up the new I/O emulate
> > function to the end of the existing ioport emulation code.  
> 
> I'm sorry, but I don't understand that last sentence. Do you mean that the ioport
> emulation code has been modified to use kvm__emulate_pio() as a fallback for when
> the port is not found in the ioport_tree?

I meant that for the transition period we have all of traditional MMIO,
traditional PIO, *and* just transformed PIO.

That means there are still PIO devices registered through ioport.c's
ioport__register(), *and* PIO devices registered through mmio.c's
kvm__register_pio(). Which means they end up in two separate PIO trees.
And only the traditional kvm__emulate_io() from ioport.c is called upon
a trap, so it needs to check both trees, which it does by calling into
kvm__emulate_pio(), shall a search in the local tree fail.

Or did you mean something else?

> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  include/kvm/kvm.h | 42 +++++++++++++++++++++++++++++----
> >  ioport.c          |  4 ++--
> >  mmio.c            | 59 +++++++++++++++++++++++++++++++++++++++--------
> >  3 files changed, 89 insertions(+), 16 deletions(-)
> >
> > diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> > index ee99c28e..14f9d58b 100644
> > --- a/include/kvm/kvm.h
> > +++ b/include/kvm/kvm.h
> > @@ -27,10 +27,16 @@
> >  #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
> >  #endif
> >  
> > +#define IOTRAP_BUS_MASK		0xf  
> 
> It's not immediately obvious what this mask does. It turns out it's used to mask
> the enum flags defined in the header devices.h, header which is not included in
> this file.
> 
> The flag names we pass to kvm__register_iotrap() are slightly inconsistent
> (DEVICE_BUS_PCI, DEVICE_BUS_MMIO and IOTRAP_COALESCE), where DEVICE_BUS_{PCI,
> MMIO} come from devices.h as an enum. I was wondering if I'm missing something and
> there is a particular reason why we don't define our own flags for that here
> (something like IOTRAP_PIO and IOTRAP_MMIO).

I am not sure why this would be needed?
We already define and use DEVICE_BUS_x elsewhere, so why not re-use it?

> If we do decide to keep the flags from devices.h, I think it would be worth it to
> have a compile time check (with BUILD_BUG_ON) that IOTRAP_BUS_MASK is >=
> DEVICES_BUS_MAX, which would also be a good indication of where those flags are
> coming from.

Well, if that makes you happy, I am not sure we gain another 13 bus
types anytime soon, though ;-)
 
> 
> > +#define IOTRAP_COALESCE		(1U << 4)
> > +
> >  #define DEFINE_KVM_EXT(ext)		\
> >  	.name = #ext,			\
> >  	.code = ext
> >  
> > +struct kvm_cpu;
> > +typedef void (*mmio_handler_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> > +				u32 len, u8 is_write, void *ptr);
> >  typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);
> >  
> >  enum {
> > @@ -113,6 +119,8 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
> >  void kvm__irq_trigger(struct kvm *kvm, int irq);
> >  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
> >  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
> > +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> > +		      int direction, int size, u32 count);
> >  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
> >  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
> >  		      enum kvm_mem_type type);
> > @@ -136,10 +144,36 @@ static inline int kvm__reserve_mem(struct kvm *kvm, u64 guest_phys, u64 size)
> >  				 KVM_MEM_TYPE_RESERVED);
> >  }
> >  
> > -int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
> > -				    void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
> > -				    void *ptr);
> > -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
> > +int __must_check kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 len,
> > +				      mmio_handler_fn mmio_fn, void *ptr,
> > +				      unsigned int flags);
> > +
> > +static inline
> > +int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr,
> > +				    u64 phys_addr_len, bool coalesce,
> > +				    mmio_handler_fn mmio_fn, void *ptr)
> > +{
> > +	return kvm__register_iotrap(kvm, phys_addr, phys_addr_len, mmio_fn, ptr,
> > +			DEVICE_BUS_MMIO | (coalesce ? IOTRAP_COALESCE : 0));
> > +}
> > +static inline
> > +int __must_check kvm__register_pio(struct kvm *kvm, u16 port, u16 len,
> > +				   mmio_handler_fn mmio_fn, void *ptr)
> > +{
> > +	return kvm__register_iotrap(kvm, port, len, mmio_fn, ptr,
> > +				    DEVICE_BUS_IOPORT);
> > +}
> > +
> > +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags);
> > +static inline bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
> > +{
> > +	return kvm__deregister_iotrap(kvm, phys_addr, DEVICE_BUS_MMIO);
> > +}
> > +static inline bool kvm__deregister_pio(struct kvm *kvm, u16 port)
> > +{
> > +	return kvm__deregister_iotrap(kvm, port, DEVICE_BUS_IOPORT);
> > +}
> > +
> >  void kvm__reboot(struct kvm *kvm);
> >  void kvm__pause(struct kvm *kvm);
> >  void kvm__continue(struct kvm *kvm);
> > diff --git a/ioport.c b/ioport.c
> > index b98836d3..204d8103 100644
> > --- a/ioport.c
> > +++ b/ioport.c
> > @@ -147,7 +147,8 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
> >  
> >  	entry = ioport_get(&ioport_tree, port);
> >  	if (!entry)
> > -		goto out;
> > +		return kvm__emulate_pio(vcpu, port, data, direction,
> > +					size, count);  
> 
> I have to admit this gave me pause because this patch doesn't add any users for
> kvm__register_pio() (although with this change the behaviour of kvm__emulate_io()
> remains exactly the same). Do you think this change would fit better in patch #7,
> where the first user for kvm__register_pio() is added, or do you prefer it here?

I think it logically belongs here, as we introduce the
kvm__emulate_pio() function here as well. Otherwise this function would
have no caller. As it is now, it's just a "coincidence" that no one
actually called kvm__register_pio() so far. This also makes the other
patches movable and replaceable: this patch prepares the stage, the
follow-up patches just fill it.

> >  
> >  	ops	= entry->ops;
> >  
> > @@ -162,7 +163,6 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16
> > port, void *data, int direction, 
> >  	ioport_put(&ioport_tree, entry);
> >  
> > -out:
> >  	if (ret)
> >  		return true;
> >  
> > diff --git a/mmio.c b/mmio.c
> > index cd141cd3..4cce1901 100644
> > --- a/mmio.c
> > +++ b/mmio.c
> > @@ -19,13 +19,14 @@ static DEFINE_MUTEX(mmio_lock);
> >  
> >  struct mmio_mapping {
> >  	struct rb_int_node	node;
> > -	void			(*mmio_fn)(struct kvm_cpu
> > *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
> > +	mmio_handler_fn		mmio_fn;
> >  	void			*ptr;
> >  	u32			refcount;
> >  	bool			remove;
> >  };
> >  
> >  static struct rb_root mmio_tree = RB_ROOT;
> > +static struct rb_root pio_tree = RB_ROOT;
> >  
> >  static struct mmio_mapping *mmio_search(struct rb_root *root, u64
> > addr, u64 len) {
> > @@ -103,9 +104,9 @@ static void mmio_put(struct kvm *kvm, struct
> > rb_root *root, struct mmio_mapping mutex_unlock(&mmio_lock);
> >  }
> >  
> > -int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64
> > phys_addr_len, bool coalesce,
> > -		       void (*mmio_fn)(struct kvm_cpu *vcpu, u64
> > addr, u8 *data, u32 len, u8 is_write, void *ptr),
> > -			void *ptr)
> > +int kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64
> > phys_addr_len,
> > +			 mmio_handler_fn mmio_fn, void *ptr,
> > +			 unsigned int flags)
> >  {
> >  	struct mmio_mapping *mmio;
> >  	struct kvm_coalesced_mmio_zone zone;
> > @@ -127,7 +128,7 @@ int kvm__register_mmio(struct kvm *kvm, u64
> > phys_addr, u64 phys_addr_len, bool c .remove		= false,
> >  	};
> >  
> > -	if (coalesce) {
> > +	if (flags & IOTRAP_COALESCE) {  
> 
> There is no such flag being used in ioport.c, is it valid to have the
> flags DEVICE_BUS_IOPORT and IOTRAP_COALESCE set at the same time?

Well, yes and no: Yes, as this maps to MMIO on non-x86, so
theoretically could use the flag. No, as no one registering a trap
handler through kvm__register_pio() would ever have the chance to set
this flag.
I can check for the registration being for the MMIO bus before entering
the "if" branch, if that is what you mean?

> 
> >  		zone = (struct kvm_coalesced_mmio_zone) {
> >  			.addr	= phys_addr,
> >  			.size	= phys_addr_len,
> > @@ -139,18 +140,27 @@ int kvm__register_mmio(struct kvm *kvm, u64
> > phys_addr, u64 phys_addr_len, bool c }
> >  	}
> >  	mutex_lock(&mmio_lock);
> > -	ret = mmio_insert(&mmio_tree, mmio);
> > +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
> > +		ret = mmio_insert(&pio_tree, mmio);
> > +	else
> > +		ret = mmio_insert(&mmio_tree, mmio);
> >  	mutex_unlock(&mmio_lock);
> >  
> >  	return ret;
> >  }
> >  
> > -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
> > +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr,
> > unsigned int flags) {
> >  	struct mmio_mapping *mmio;
> > +	struct rb_root *tree;
> > +
> > +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
> > +		tree = &pio_tree;
> > +	else
> > +		tree = &mmio_tree;
> >  
> >  	mutex_lock(&mmio_lock);
> > -	mmio = mmio_search_single(&mmio_tree, phys_addr);
> > +	mmio = mmio_search_single(tree, phys_addr);
> >  	if (mmio == NULL) {
> >  		mutex_unlock(&mmio_lock);
> >  		return false;
> > @@ -167,7 +177,7 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64
> > phys_addr)
> >  	 * called mmio_put(). This will trigger use-after-free
> > errors on VCPU0. */
> >  	if (mmio->refcount == 0)
> > -		mmio_deregister(kvm, &mmio_tree, mmio);
> > +		mmio_deregister(kvm, tree, mmio);
> >  	else
> >  		mmio->remove = true;
> >  	mutex_unlock(&mmio_lock);
> > @@ -175,7 +185,8 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64
> > phys_addr) return true;
> >  }
> >  
> > -bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8
> > *data, u32 len, u8 is_write) +bool kvm__emulate_mmio(struct kvm_cpu
> > *vcpu, u64 phys_addr, u8 *data,
> > +		       u32 len, u8 is_write)  
> 
> I don't think style changes should be part of this patch, the patch
> is large enough as it is.

I see, I just figured it's not worth a separate patch either.

Cheers,
Andre

> >  {
> >  	struct mmio_mapping *mmio;
> >  
> > @@ -194,3 +205,31 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu,
> > u64 phys_addr, u8 *data, u32 len, u out:
> >  	return true;
> >  }
> > +
> > +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> > +		     int direction, int size, u32 count)
> > +{
> > +	struct mmio_mapping *mmio;
> > +	bool is_write = direction == KVM_EXIT_IO_OUT;
> > +
> > +	mmio = mmio_get(&pio_tree, port, size);
> > +	if (!mmio) {
> > +		if (vcpu->kvm->cfg.ioport_debug) {
> > +			fprintf(stderr, "IO error: %s port=%x,
> > size=%d, count=%u\n",
> > +				to_direction(direction), port,
> > size, count); +
> > +			return false;
> > +		}
> > +		return true;
> > +	}
> > +
> > +	while (count--) {
> > +		mmio->mmio_fn(vcpu, port, data, size, is_write,
> > mmio->ptr); +
> > +		data += size;
> > +	}
> > +
> > +	mmio_put(vcpu->kvm, &pio_tree, mmio);
> > +
> > +	return true;
> > +}  


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

* Re: [PATCH kvmtool 05/21] hw/i8042: Clean up data types
  2021-02-11 16:55   ` Alexandru Elisei
@ 2021-02-17 17:46     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-17 17:46 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 16:55:43 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> 
> > The i8042 is clearly an 8-bit era device, so there is little room for
> > 32-bit registers.
> > Clean up the data types used.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/i8042.c | 20 ++++++++++----------
> >  1 file changed, 10 insertions(+), 10 deletions(-)
> >
> > diff --git a/hw/i8042.c b/hw/i8042.c
> > index 37a99a2d..36ee183f 100644
> > --- a/hw/i8042.c
> > +++ b/hw/i8042.c
> > @@ -64,11 +64,11 @@
> >  struct kbd_state {
> >  	struct kvm		*kvm;
> >  
> > -	char			kq[QUEUE_SIZE];	/* Keyboard queue */
> > +	u8			kq[QUEUE_SIZE];	/* Keyboard queue */
> >  	int			kread, kwrite;	/* Indexes into the queue */
> >  	int			kcount;		/* number of elements in queue */
> >  
> > -	char			mq[QUEUE_SIZE];
> > +	u8			mq[QUEUE_SIZE];
> >  	int			mread, mwrite;
> >  	int			mcount;  
> 
> I think the write_cmd field further down should also be u8 because it stores the
> first byte of a command (and it's set only to an 8 bit value in kbd_write_command()).

Yes, looks like it, will change it on the way. I guess I wanted to
suppress my rewrite-everything complex ;-)

If you allow, I will also fix the confusing indentation bug in the big
switch statement on the way.
 
> Otherwise, it looks ok to me. osdev wiki seems to confirm that the device is
> indeed 8 bit only, and all the registers are 8 bit now:
> 
> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

Thanks!
Andre

> 
> >  
> > @@ -173,9 +173,9 @@ static void kbd_write_command(struct kvm *kvm, u8 val)
> >  /*
> >   * Called when the OS reads from port 0x60 (PS/2 data)
> >   */
> > -static u32 kbd_read_data(void)
> > +static u8 kbd_read_data(void)
> >  {
> > -	u32 ret;
> > +	u8 ret;
> >  	int i;
> >  
> >  	if (state.kcount != 0) {
> > @@ -202,9 +202,9 @@ static u32 kbd_read_data(void)
> >  /*
> >   * Called when the OS read from port 0x64, the command port
> >   */
> > -static u32 kbd_read_status(void)
> > +static u8 kbd_read_status(void)
> >  {
> > -	return (u32)state.status;
> > +	return state.status;
> >  }
> >  
> >  /*
> > @@ -212,7 +212,7 @@ static u32 kbd_read_status(void)
> >   * Things written here are generally arguments to commands previously
> >   * written to port 0x64 and stored in state.write_cmd
> >   */
> > -static void kbd_write_data(u32 val)
> > +static void kbd_write_data(u8 val)
> >  {
> >  	switch (state.write_cmd) {
> >  	case I8042_CMD_CTL_WCTR:
> > @@ -304,8 +304,8 @@ static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *
> >  		break;
> >  	}
> >  	case I8042_DATA_REG: {
> > -		u32 value = kbd_read_data();
> > -		ioport__write32(data, value);
> > +		u8 value = kbd_read_data();
> > +		ioport__write8(data, value);
> >  		break;
> >  	}
> >  	case I8042_PORT_B_REG: {
> > @@ -328,7 +328,7 @@ static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void
> >  		break;
> >  	}
> >  	case I8042_DATA_REG: {
> > -		u32 value = ioport__read32(data);
> > +		u8 value = ioport__read8(data);
> >  		kbd_write_data(value);
> >  		break;
> >  	}  


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

* Re: [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2021-02-11 17:23   ` Alexandru Elisei
@ 2021-02-18 10:34     ` Andre Przywara
  2021-02-18 11:17       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 10:34 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 11 Feb 2021 17:23:13 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > With the planned retirement of the special ioport emulation code, we
> > need to provide an emulation function compatible with the MMIO
> > prototype.
> >
> > Adjust the trap handler to use that new function, and provide shims to
> > implement the old ioport interface, for now.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
> >  1 file changed, 34 insertions(+), 34 deletions(-)
> >
> > diff --git a/hw/i8042.c b/hw/i8042.c
> > index 36ee183f..eb1f9d28 100644
> > --- a/hw/i8042.c
> > +++ b/hw/i8042.c
> > @@ -292,52 +292,52 @@ static void kbd_reset(void)
> >  	};
> >  }
> >  
> > -/*
> > - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> > - */
> > -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > +static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> > +		   u8 is_write, void *ptr)
> >  {
> > -	switch (port) {
> > -	case I8042_COMMAND_REG: {
> > -		u8 value = kbd_read_status();
> > -		ioport__write8(data, value);
> > +	u8 value;
> > +
> > +	if (is_write)
> > +		value = ioport__read8(data);
> > +
> > +	switch (addr) {
> > +	case I8042_COMMAND_REG:
> > +		if (is_write)
> > +			kbd_write_command(vcpu->kvm, value);
> > +		else
> > +			value = kbd_read_status();
> >  		break;
> > -	}
> > -	case I8042_DATA_REG: {
> > -		u8 value = kbd_read_data();
> > -		ioport__write8(data, value);
> > +	case I8042_DATA_REG:
> > +		if (is_write)
> > +			kbd_write_data(value);
> > +		else
> > +			value = kbd_read_data();
> >  		break;
> > -	}
> > -	case I8042_PORT_B_REG: {
> > -		ioport__write8(data, 0x20);
> > +	case I8042_PORT_B_REG:
> > +		if (!is_write)
> > +			value = 0x20;
> >  		break;
> > -	}
> >  	default:
> > -		return false;
> > +		return;  
> 
> Any particular reason for removing the false return value? I don't see it
> mentioned in the commit message. Otherwise this is identical to the two functions
> it replaces.

Because the MMIO handler prototype is void, in contrast to the PIO one.
Since on returning "false" we only seem to panic kvmtool, this is of
quite limited use, I'd say.

> >  	}
> >  
> > +	if (!is_write)
> > +		ioport__write8(data, value);
> > +}
> > +
> > +/*
> > + * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> > + */
> > +static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > +{
> > +	kbd_io(vcpu, port, data, size, false, NULL);  
> 
> is_write is an u8, not a bool.

Right, will fix this.

> I never could wrap my head around the ioport convention of "in" (read) and "out"
> (write). To be honest, changing is_write changed to an enum so it's crystal clear
> what is happening would help with that a lot, but I guess that's a separate patch.

"in" and "out" are the x86 assembly mnemonics, but it's indeed
confusing, because the device side has a different view (CPU "in" means
pushing data "out" of the device). I usually look at the code to see
what it's actually meant to do.
So yeah, I feel like a lot of those device emulations could use
some update. but that's indeed something for another day.

Cheers,
Andre

> > +
> >  	return true;
> >  }
> >  
> >  static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> >  {
> > -	switch (port) {
> > -	case I8042_COMMAND_REG: {
> > -		u8 value = ioport__read8(data);
> > -		kbd_write_command(vcpu->kvm, value);
> > -		break;
> > -	}
> > -	case I8042_DATA_REG: {
> > -		u8 value = ioport__read8(data);
> > -		kbd_write_data(value);
> > -		break;
> > -	}
> > -	case I8042_PORT_B_REG: {
> > -		break;
> > -	}
> > -	default:
> > -		return false;
> > -	}
> > +	kbd_io(vcpu, port, data, size, true, NULL);
> >  
> >  	return true;
> >  }  


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

* Re: [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2021-02-18 10:34     ` Andre Przywara
@ 2021-02-18 11:17       ` Alexandru Elisei
  2021-02-18 11:48         ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-18 11:17 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/18/21 10:34 AM, Andre Przywara wrote:
> On Thu, 11 Feb 2021 17:23:13 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
>> Hi Andre,
>>
>> On 12/10/20 2:28 PM, Andre Przywara wrote:
>>> With the planned retirement of the special ioport emulation code, we
>>> need to provide an emulation function compatible with the MMIO
>>> prototype.
>>>
>>> Adjust the trap handler to use that new function, and provide shims to
>>> implement the old ioport interface, for now.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
>>>  1 file changed, 34 insertions(+), 34 deletions(-)
>>>
>>> diff --git a/hw/i8042.c b/hw/i8042.c
>>> index 36ee183f..eb1f9d28 100644
>>> --- a/hw/i8042.c
>>> +++ b/hw/i8042.c
>>> @@ -292,52 +292,52 @@ static void kbd_reset(void)
>>>  	};
>>>  }
>>>  
>>> -/*
>>> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
>>> - */
>>> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>> +static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>>> +		   u8 is_write, void *ptr)
>>>  {
>>> -	switch (port) {
>>> -	case I8042_COMMAND_REG: {
>>> -		u8 value = kbd_read_status();
>>> -		ioport__write8(data, value);
>>> +	u8 value;
>>> +
>>> +	if (is_write)
>>> +		value = ioport__read8(data);
>>> +
>>> +	switch (addr) {
>>> +	case I8042_COMMAND_REG:
>>> +		if (is_write)
>>> +			kbd_write_command(vcpu->kvm, value);
>>> +		else
>>> +			value = kbd_read_status();
>>>  		break;
>>> -	}
>>> -	case I8042_DATA_REG: {
>>> -		u8 value = kbd_read_data();
>>> -		ioport__write8(data, value);
>>> +	case I8042_DATA_REG:
>>> +		if (is_write)
>>> +			kbd_write_data(value);
>>> +		else
>>> +			value = kbd_read_data();
>>>  		break;
>>> -	}
>>> -	case I8042_PORT_B_REG: {
>>> -		ioport__write8(data, 0x20);
>>> +	case I8042_PORT_B_REG:
>>> +		if (!is_write)
>>> +			value = 0x20;
>>>  		break;
>>> -	}
>>>  	default:
>>> -		return false;
>>> +		return;  
>> Any particular reason for removing the false return value? I don't see it
>> mentioned in the commit message. Otherwise this is identical to the two functions
>> it replaces.
> Because the MMIO handler prototype is void, in contrast to the PIO one.
> Since on returning "false" we only seem to panic kvmtool, this is of
> quite limited use, I'd say.

Actually, in ioport.c::kvm__emulate_io(), if kvm->cfg.ioport_debug is true, it
will print an error and then panic in kvm_cpu__start(); otherwise the error is
silently ignored. serial.c is another device where an unknown register returns
false. In rtc.c, the unknown register is ignored. cfi_flash.c prints debugging
information. So I guess kvmtool implements all possible methods of handling an
unknown register *at the same time*, so it's up to you how you want to handle it.

>>>  	}
>>>  
>>> +	if (!is_write)
>>> +		ioport__write8(data, value);
>>> +}
>>> +
>>> +/*
>>> + * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
>>> + */
>>> +static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>> +{
>>> +	kbd_io(vcpu, port, data, size, false, NULL);  
>> is_write is an u8, not a bool.
> Right, will fix this.
>
>> I never could wrap my head around the ioport convention of "in" (read) and "out"
>> (write). To be honest, changing is_write changed to an enum so it's crystal clear
>> what is happening would help with that a lot, but I guess that's a separate patch.
> "in" and "out" are the x86 assembly mnemonics, but it's indeed
> confusing, because the device side has a different view (CPU "in" means
> pushing data "out" of the device). I usually look at the code to see
> what it's actually meant to do.
> So yeah, I feel like a lot of those device emulations could use
> some update. but that's indeed something for another day.

Agreed.

Thanks,

Alex

>
> Cheers,
> Andre
>
>>> +
>>>  	return true;
>>>  }
>>>  
>>>  static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>>  {
>>> -	switch (port) {
>>> -	case I8042_COMMAND_REG: {
>>> -		u8 value = ioport__read8(data);
>>> -		kbd_write_command(vcpu->kvm, value);
>>> -		break;
>>> -	}
>>> -	case I8042_DATA_REG: {
>>> -		u8 value = ioport__read8(data);
>>> -		kbd_write_data(value);
>>> -		break;
>>> -	}
>>> -	case I8042_PORT_B_REG: {
>>> -		break;
>>> -	}
>>> -	default:
>>> -		return false;
>>> -	}
>>> +	kbd_io(vcpu, port, data, size, true, NULL);
>>>  
>>>  	return true;
>>>  }  

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

* Re: [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2021-02-18 11:17       ` Alexandru Elisei
@ 2021-02-18 11:48         ` Andre Przywara
  2021-02-22 16:03           ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 11:48 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 18 Feb 2021 11:17:58 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 2/18/21 10:34 AM, Andre Przywara wrote:
> > On Thu, 11 Feb 2021 17:23:13 +0000
> > Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> >  
> >> Hi Andre,
> >>
> >> On 12/10/20 2:28 PM, Andre Przywara wrote:  
> >>> With the planned retirement of the special ioport emulation code, we
> >>> need to provide an emulation function compatible with the MMIO
> >>> prototype.
> >>>
> >>> Adjust the trap handler to use that new function, and provide shims to
> >>> implement the old ioport interface, for now.
> >>>
> >>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>> ---
> >>>  hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
> >>>  1 file changed, 34 insertions(+), 34 deletions(-)
> >>>
> >>> diff --git a/hw/i8042.c b/hw/i8042.c
> >>> index 36ee183f..eb1f9d28 100644
> >>> --- a/hw/i8042.c
> >>> +++ b/hw/i8042.c
> >>> @@ -292,52 +292,52 @@ static void kbd_reset(void)
> >>>  	};
> >>>  }
> >>>  
> >>> -/*
> >>> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> >>> - */
> >>> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> >>> +static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> >>> +		   u8 is_write, void *ptr)
> >>>  {
> >>> -	switch (port) {
> >>> -	case I8042_COMMAND_REG: {
> >>> -		u8 value = kbd_read_status();
> >>> -		ioport__write8(data, value);
> >>> +	u8 value;
> >>> +
> >>> +	if (is_write)
> >>> +		value = ioport__read8(data);
> >>> +
> >>> +	switch (addr) {
> >>> +	case I8042_COMMAND_REG:
> >>> +		if (is_write)
> >>> +			kbd_write_command(vcpu->kvm, value);
> >>> +		else
> >>> +			value = kbd_read_status();
> >>>  		break;
> >>> -	}
> >>> -	case I8042_DATA_REG: {
> >>> -		u8 value = kbd_read_data();
> >>> -		ioport__write8(data, value);
> >>> +	case I8042_DATA_REG:
> >>> +		if (is_write)
> >>> +			kbd_write_data(value);
> >>> +		else
> >>> +			value = kbd_read_data();
> >>>  		break;
> >>> -	}
> >>> -	case I8042_PORT_B_REG: {
> >>> -		ioport__write8(data, 0x20);
> >>> +	case I8042_PORT_B_REG:
> >>> +		if (!is_write)
> >>> +			value = 0x20;
> >>>  		break;
> >>> -	}
> >>>  	default:
> >>> -		return false;
> >>> +		return;    
> >> Any particular reason for removing the false return value? I don't see it
> >> mentioned in the commit message. Otherwise this is identical to the two functions
> >> it replaces.  
> > Because the MMIO handler prototype is void, in contrast to the PIO one.
> > Since on returning "false" we only seem to panic kvmtool, this is of
> > quite limited use, I'd say.  
> 
> Actually, in ioport.c::kvm__emulate_io(), if kvm->cfg.ioport_debug is true, it
> will print an error and then panic in kvm_cpu__start(); otherwise the error is
> silently ignored. serial.c is another device where an unknown register returns
> false. In rtc.c, the unknown register is ignored. cfi_flash.c prints debugging
> information. So I guess kvmtool implements all possible methods of handling an
> unknown register *at the same time*, so it's up to you how you want to handle it.

Well, the MMIO prototype we are going to use is void anyway, so it's
just one patch earlier that we get this new behaviour.
For handling MMIO errors:
- Hardware MMIO doesn't have a back channel: if the MMIO write triggers
  some error condition, the device would need to deal with it (setting
  internal error state, ignore, etc.). On some systems the device could
  throw some kind of bus error or SError, but this is a rather drastic
  measure, and is certainly not exercised by those ancient devices.
- Any kind of error reporting which can be triggered by a guest is
  frowned upon: it could spam the console or some log file, and so
  impact host operation. At the end an administrator can't do much about
  it, anyway.
- Which leaves the only use to some kvmtool developer debugging some
  device emulation or investigating weird guest behaviour. And in this
  case we can more easily have a debug message *inside* the device
  emulation code, can't we?

And since the MMIO handler prototype is void, we have no choice anyway,
at least not without another huge (and pointless) series to change
those user as well ;-)

Cheers,
Andre

> >>>  	}
> >>>  
> >>> +	if (!is_write)
> >>> +		ioport__write8(data, value);
> >>> +}
> >>> +
> >>> +/*
> >>> + * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> >>> + */
> >>> +static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> >>> +{
> >>> +	kbd_io(vcpu, port, data, size, false, NULL);    
> >> is_write is an u8, not a bool.  
> > Right, will fix this.
> >  
> >> I never could wrap my head around the ioport convention of "in" (read) and "out"
> >> (write). To be honest, changing is_write changed to an enum so it's crystal clear
> >> what is happening would help with that a lot, but I guess that's a separate patch.  
> > "in" and "out" are the x86 assembly mnemonics, but it's indeed
> > confusing, because the device side has a different view (CPU "in" means
> > pushing data "out" of the device). I usually look at the code to see
> > what it's actually meant to do.
> > So yeah, I feel like a lot of those device emulations could use
> > some update. but that's indeed something for another day.  
> 
> Agreed.
> 
> Thanks,
> 
> Alex
> 
> >
> > Cheers,
> > Andre
> >  
> >>> +
> >>>  	return true;
> >>>  }
> >>>  
> >>>  static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> >>>  {
> >>> -	switch (port) {
> >>> -	case I8042_COMMAND_REG: {
> >>> -		u8 value = ioport__read8(data);
> >>> -		kbd_write_command(vcpu->kvm, value);
> >>> -		break;
> >>> -	}
> >>> -	case I8042_DATA_REG: {
> >>> -		u8 value = ioport__read8(data);
> >>> -		kbd_write_data(value);
> >>> -		break;
> >>> -	}
> >>> -	case I8042_PORT_B_REG: {
> >>> -		break;
> >>> -	}
> >>> -	default:
> >>> -		return false;
> >>> -	}
> >>> +	kbd_io(vcpu, port, data, size, true, NULL);
> >>>  
> >>>  	return true;
> >>>  }    


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

* Re: [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers
  2021-02-12 10:41   ` Alexandru Elisei
@ 2021-02-18 12:09     ` Andre Przywara
  2021-02-22 16:19       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 12:09 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Fri, 12 Feb 2021 10:41:20 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > Now that the PC keyboard has a trap handler adhering to the MMIO fault
> > handler prototype, let's switch over to the joint registration routine.
> >
> > This allows us to get rid of the ioport shim routines.
> >
> > Make the kbd_init() function static on the way.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/i8042.c          | 30 ++++--------------------------
> >  include/kvm/i8042.h |  1 -
> >  2 files changed, 4 insertions(+), 27 deletions(-)
> >
> > diff --git a/hw/i8042.c b/hw/i8042.c
> > index eb1f9d28..91d79dc4 100644
> > --- a/hw/i8042.c
> > +++ b/hw/i8042.c
> > @@ -325,40 +325,18 @@ static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> >  		ioport__write8(data, value);
> >  }
> >  
> > -/*
> > - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
> > - */
> > -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	kbd_io(vcpu, port, data, size, false, NULL);
> > -
> > -	return true;
> > -}
> > -
> > -static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	kbd_io(vcpu, port, data, size, true, NULL);
> > -
> > -	return true;
> > -}
> > -
> > -static struct ioport_operations kbd_ops = {
> > -	.io_in		= kbd_in,
> > -	.io_out		= kbd_out,
> > -};
> > -
> > -int kbd__init(struct kvm *kvm)
> > +static int kbd__init(struct kvm *kvm)
> >  {
> >  	int r;
> >  
> >  	kbd_reset();
> >  	state.kvm = kvm;
> > -	r = ioport__register(kvm, I8042_DATA_REG, &kbd_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, I8042_DATA_REG, 2, kbd_io, NULL);  
> 
> I guess you are registering two addresses here to cover I8042_PORT_B_REG, right?
> Might be worth a comment.

I am registering two ports because the original code did, and I didn't
dare to touch this. I guess we put this on the wishlist for the device
emulation fixup series? ;-)

Maybe the intention was to just *reserve* those ports?

> 
> >  	if (r < 0)
> >  		return r;
> > -	r = ioport__register(kvm, I8042_COMMAND_REG, &kbd_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, I8042_COMMAND_REG, 2, kbd_io, NULL);  
> 
> Shouldn't length be 1? The emulation should work only for address 0x64
> (command/status register), right? Or am I missing something?

I don't think you are, same as above. Maybe some weird guest is using
half-word accesses (outw)?

Cheers,
Andre


> 
> Thanks,
> 
> Alex
> 
> >  	if (r < 0) {
> > -		ioport__unregister(kvm, I8042_DATA_REG);
> > +		kvm__deregister_pio(kvm, I8042_DATA_REG);
> >  		return r;
> >  	}
> >  
> > diff --git a/include/kvm/i8042.h b/include/kvm/i8042.h
> > index 3b4ab688..cd4ae6bb 100644
> > --- a/include/kvm/i8042.h
> > +++ b/include/kvm/i8042.h
> > @@ -7,6 +7,5 @@ struct kvm;
> >  
> >  void mouse_queue(u8 c);
> >  void kbd_queue(u8 c);
> > -int kbd__init(struct kvm *kvm);
> >  
> >  #endif  


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

* Re: [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses
  2021-02-17 16:48   ` Alexandru Elisei
@ 2021-02-18 12:18     ` Alexandru Elisei
  2021-02-18 16:38       ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-18 12:18 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: linux-arm-kernel, Marc Zyngier, kvmarm, kvm

Hi Andre,

On 2/17/21 4:48 PM, Alexandru Elisei wrote:
> Hi Andre,
>
> On 12/10/20 2:29 PM, Andre Przywara wrote:
>> Using the UART devices at their legacy I/O addresses as set by IBM in
>> 1981 was a kludge we used for simplicity on ARM platforms as well.
>> However this imposes problems due to their missing alignment and overlap
>> with the PCI I/O address space.
>>
>> Now that we can switch a device easily between using ioports and MMIO,
>> let's move the UARTs out of the first 4K of memory on ARM platforms.
>>
>> That should be transparent for well behaved guests, since the change is
>> naturally reflected in the device tree. Even "earlycon" keeps working,
>> as the stdout-path property is adjusted automatically.
>>
>> People providing direct earlycon parameters via the command line need to
>> adjust it to: "earlycon=uart,mmio,0x1000000".
>>
>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>> ---
>>  hw/serial.c | 52 ++++++++++++++++++++++++++++++++++++----------------
>>  1 file changed, 36 insertions(+), 16 deletions(-)
>>
>> diff --git a/hw/serial.c b/hw/serial.c
>> index d840eebc..00fb3aa8 100644
>> --- a/hw/serial.c
>> +++ b/hw/serial.c
>> @@ -13,6 +13,24 @@
>>  
>>  #include <pthread.h>
>>  
>> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
>> +#define serial_iobase(nr)	(0x1000000 + (nr) * 0x1000)
>> +#define serial_irq(nr)		(32 + (nr))
>> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
>> +#else
>> +#define serial_iobase_0		0x3f8
>> +#define serial_iobase_1		0x2f8
>> +#define serial_iobase_2		0x3e8
>> +#define serial_iobase_3		0x2e8
>> +#define serial_irq_0		4
>> +#define serial_irq_1		3
>> +#define serial_irq_2		4
>> +#define serial_irq_3		3
> Nitpick: serial_iobase_* and serial_irq_* could be changed to have two leading
> underscores, to stress the fact that they are helpers for serial_iobase() and
> serial_irq() and are not meant to be used by themselves. But that's just personal
> preference, otherwise the patch looks really nice and clean:
>
> Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>

I gave it more thought and I think I spoke too soon. I think it would be good to
document in the commit message how you came to the base MMIO address and size
(even if it was just a nice looking number). Also, the CFI flash device has its
memory range described in the memory layout for the architecture, in
arm/include/arm-common/kvm-arch.h. I think it would be a good idea to put the
serial region there, to prevent regressions in the future.

I did the math to make sure there's no overlap with the ioport region (16M >> 16K)
or the flash region (16M + 0x4000 < 32M). I also tested the changes with a kernel
with 4K and 64K pages (I can't access any hardware with 16K pages at the moment),
and everything worked as expected.

Thanks,

Alex

> Thanks,
>
> Alex
>
>> +#define serial_iobase(nr)	serial_iobase_##nr
>> +#define serial_irq(nr)		serial_irq_##nr
>> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
>> +#endif
>> +
>>  /*
>>   * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
>>   * expects that for autodetection.
>> @@ -27,7 +45,7 @@ struct serial8250_device {
>>  	struct mutex		mutex;
>>  	u8			id;
>>  
>> -	u16			iobase;
>> +	u32			iobase;
>>  	u8			irq;
>>  	u8			irq_state;
>>  	int			txcnt;
>> @@ -65,56 +83,56 @@ static struct serial8250_device devices[] = {
>>  	/* ttyS0 */
>>  	[0]	= {
>>  		.dev_hdr = {
>> -			.bus_type	= DEVICE_BUS_IOPORT,
>> +			.bus_type	= SERIAL8250_BUS_TYPE,
>>  			.data		= serial8250_generate_fdt_node,
>>  		},
>>  		.mutex			= MUTEX_INITIALIZER,
>>  
>>  		.id			= 0,
>> -		.iobase			= 0x3f8,
>> -		.irq			= 4,
>> +		.iobase			= serial_iobase(0),
>> +		.irq			= serial_irq(0),
>>  
>>  		SERIAL_REGS_SETTING
>>  	},
>>  	/* ttyS1 */
>>  	[1]	= {
>>  		.dev_hdr = {
>> -			.bus_type	= DEVICE_BUS_IOPORT,
>> +			.bus_type	= SERIAL8250_BUS_TYPE,
>>  			.data		= serial8250_generate_fdt_node,
>>  		},
>>  		.mutex			= MUTEX_INITIALIZER,
>>  
>>  		.id			= 1,
>> -		.iobase			= 0x2f8,
>> -		.irq			= 3,
>> +		.iobase			= serial_iobase(1),
>> +		.irq			= serial_irq(1),
>>  
>>  		SERIAL_REGS_SETTING
>>  	},
>>  	/* ttyS2 */
>>  	[2]	= {
>>  		.dev_hdr = {
>> -			.bus_type	= DEVICE_BUS_IOPORT,
>> +			.bus_type	= SERIAL8250_BUS_TYPE,
>>  			.data		= serial8250_generate_fdt_node,
>>  		},
>>  		.mutex			= MUTEX_INITIALIZER,
>>  
>>  		.id			= 2,
>> -		.iobase			= 0x3e8,
>> -		.irq			= 4,
>> +		.iobase			= serial_iobase(2),
>> +		.irq			= serial_irq(2),
>>  
>>  		SERIAL_REGS_SETTING
>>  	},
>>  	/* ttyS3 */
>>  	[3]	= {
>>  		.dev_hdr = {
>> -			.bus_type	= DEVICE_BUS_IOPORT,
>> +			.bus_type	= SERIAL8250_BUS_TYPE,
>>  			.data		= serial8250_generate_fdt_node,
>>  		},
>>  		.mutex			= MUTEX_INITIALIZER,
>>  
>>  		.id			= 3,
>> -		.iobase			= 0x2e8,
>> -		.irq			= 3,
>> +		.iobase			= serial_iobase(3),
>> +		.irq			= serial_irq(3),
>>  
>>  		SERIAL_REGS_SETTING
>>  	},
>> @@ -444,7 +462,8 @@ static int serial8250__device_init(struct kvm *kvm,
>>  		return r;
>>  
>>  	ioport__map_irq(&dev->irq);
>> -	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
>> +	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
>> +				 SERIAL8250_BUS_TYPE);
>>  
>>  	return r;
>>  }
>> @@ -467,7 +486,7 @@ cleanup:
>>  	for (j = 0; j <= i; j++) {
>>  		struct serial8250_device *dev = &devices[j];
>>  
>> -		kvm__deregister_pio(kvm, dev->iobase);
>> +		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
>>  		device__unregister(&dev->dev_hdr);
>>  	}
>>  
>> @@ -483,7 +502,8 @@ int serial8250__exit(struct kvm *kvm)
>>  	for (i = 0; i < ARRAY_SIZE(devices); i++) {
>>  		struct serial8250_device *dev = &devices[i];
>>  
>> -		r = kvm__deregister_pio(kvm, dev->iobase);
>> +		r = kvm__deregister_iotrap(kvm, dev->iobase,
>> +					   SERIAL8250_BUS_TYPE);
>>  		if (r < 0)
>>  			return r;
>>  		device__unregister(&dev->dev_hdr);
> _______________________________________________
> kvmarm mailing list
> kvmarm@lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [PATCH kvmtool 21/21] hw/rtc: ARM/arm64: Use MMIO at higher addresses
  2020-12-10 14:29 ` [PATCH kvmtool 21/21] hw/rtc: " Andre Przywara
@ 2021-02-18 13:33   ` Alexandru Elisei
  2021-02-18 16:41     ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-18 13:33 UTC (permalink / raw)
  To: Andre Przywara, Will Deacon, Julien Thierry
  Cc: kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 12/10/20 2:29 PM, Andre Przywara wrote:
> Using the RTC device at its legacy I/O address as set by IBM in 1981
> was a kludge we used for simplicity on ARM platforms as well.
> However this imposes problems due to their missing alignment and overlap
> with the PCI I/O address space.
>
> Now that we can switch a device easily between using ioports and
> MMIO, let's move the RTC out of the first 4K of memory on ARM platforms.
>
> That should be transparent for well behaved guests, since the change is
> naturally reflected in the device tree.
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
>  hw/rtc.c | 24 ++++++++++++++++--------
>  1 file changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/hw/rtc.c b/hw/rtc.c
> index ee4c9102..bdb88f0f 100644
> --- a/hw/rtc.c
> +++ b/hw/rtc.c
> @@ -5,6 +5,15 @@
>  
>  #include <time.h>
>  
> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> +#define RTC_BUS_TYPE		DEVICE_BUS_MMIO
> +#define RTC_BASE_ADDRESS	0x1010000

This looks correct, the base address is the serial base address + 64k, so they
don't overlap, and it doesn't overlap with the flash memory either. Same comment
as for the serial, I think the reason for choosing this address should be
mentioned, and the region should be put in the arch memory layout file. Other than
that, the patch looks good.

Thanks,

Alex

> +#else
> +/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> +#define RTC_BUS_TYPE		DEVICE_BUS_IOPORT
> +#define RTC_BASE_ADDRESS	0x70
> +#endif
> +
>  /*
>   * MC146818 RTC registers
>   */
> @@ -49,7 +58,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>  	time_t ti;
>  
>  	if (is_write) {
> -		if (addr == 0x70) {	/* index register */
> +		if (addr == RTC_BASE_ADDRESS) {	/* index register */
>  			u8 value = ioport__read8(data);
>  
>  			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
> @@ -70,7 +79,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>  		return;
>  	}
>  
> -	if (addr == 0x70)
> +	if (addr == RTC_BASE_ADDRESS)	/* index register is write-only */
>  		return;
>  
>  	time(&ti);
> @@ -127,7 +136,7 @@ static void generate_rtc_fdt_node(void *fdt,
>  							    u8 irq,
>  							    enum irq_type))
>  {
> -	u64 reg_prop[2] = { cpu_to_fdt64(0x70), cpu_to_fdt64(2) };
> +	u64 reg_prop[2] = { cpu_to_fdt64(RTC_BASE_ADDRESS), cpu_to_fdt64(2) };
>  
>  	_FDT(fdt_begin_node(fdt, "rtc"));
>  	_FDT(fdt_property_string(fdt, "compatible", "motorola,mc146818"));
> @@ -139,7 +148,7 @@ static void generate_rtc_fdt_node(void *fdt,
>  #endif
>  
>  struct device_header rtc_dev_hdr = {
> -	.bus_type = DEVICE_BUS_IOPORT,
> +	.bus_type = RTC_BUS_TYPE,
>  	.data = generate_rtc_fdt_node,
>  };
>  
> @@ -151,8 +160,8 @@ int rtc__init(struct kvm *kvm)
>  	if (r < 0)
>  		return r;
>  
> -	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> -	r = kvm__register_pio(kvm, 0x0070, 2, cmos_ram_io, NULL);
> +	r = kvm__register_iotrap(kvm, RTC_BASE_ADDRESS, 2, cmos_ram_io, NULL,
> +				 RTC_BUS_TYPE);
>  	if (r < 0)
>  		goto out_device;
>  
> @@ -170,8 +179,7 @@ dev_init(rtc__init);
>  
>  int rtc__exit(struct kvm *kvm)
>  {
> -	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> -	kvm__deregister_pio(kvm, 0x0070);
> +	kvm__deregister_iotrap(kvm, RTC_BASE_ADDRESS, RTC_BUS_TYPE);
>  
>  	return 0;
>  }

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

* Re: [PATCH kvmtool 09/21] x86/ioport: Switch to new trap handlers
  2021-02-12 11:27   ` Alexandru Elisei
@ 2021-02-18 14:05     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 14:05 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Fri, 12 Feb 2021 11:27:59 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi Alex,

> On 12/10/20 2:28 PM, Andre Przywara wrote:
> > Now that the x86 I/O ports have trap handlers adhering to the MMIO fault
> > handler prototype, let's switch over to the joint registration routine.
> >
> > This allows us to get rid of the ioport shim routines.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  x86/ioport.c | 113 ++++++++++++++-------------------------------------
> >  1 file changed, 30 insertions(+), 83 deletions(-)
> >
> > diff --git a/x86/ioport.c b/x86/ioport.c
> > index 932da20a..87955da1 100644
> > --- a/x86/ioport.c
> > +++ b/x86/ioport.c
> > @@ -8,16 +8,6 @@ static void dummy_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> >  {
> >  }
> >  
> > -static bool debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	dummy_mmio(vcpu, port, data, size, true, NULL);
> > -	return 0;
> > -}  
> 
> 0 is false in boolean logic, which means that emulation fails according to the
> (old) ioport emulation code (ioport.c::kvm__emulate_io()).
> 
> So I guess I have a few questions:
> 
> - Is this a bug in the emulation code, where the author thought that
> debug_io_out() returns an int, and in that case 0 actually means success?

Wading through the swamp of the git history it looks like failure is
intentional, it should be used together with --debug-ioport, to trigger
that print there.
 
> - If writing to the debug port is rightfully considered an error, do we care
> enough about it to print something to stdout like kvm__emulate_io() does when
> debug_io_out() returns false?

I think you are right, we should print something here.

Cheers,
Andre

> > -
> > -static struct ioport_operations debug_ops = {
> > -	.io_out		= debug_io_out,
> > -};
> > -
> >  static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> >  			       u32 len, u8 is_write, void *ptr)
> >  {
> > @@ -31,37 +21,6 @@ static void seabios_debug_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> >  	putchar(ch);
> >  }
> >  
> > -static bool seabios_debug_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	seabios_debug_mmio(vcpu, port, data, size, true, NULL);
> > -	return 0;
> > -}
> > -
> > -static struct ioport_operations seabios_debug_ops = {
> > -	.io_out		= seabios_debug_io_out,
> > -};
> > -
> > -static bool dummy_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	dummy_mmio(vcpu, port, data, size, false, NULL);
> > -	return true;
> > -}
> > -
> > -static bool dummy_io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	dummy_mmio(vcpu, port, data, size, true, NULL);
> > -	return true;
> > -}
> > -
> > -static struct ioport_operations dummy_read_write_ioport_ops = {
> > -	.io_in		= dummy_io_in,
> > -	.io_out		= dummy_io_out,
> > -};
> > -
> > -static struct ioport_operations dummy_write_only_ioport_ops = {
> > -	.io_out		= dummy_io_out,
> > -};
> > -
> >  /*
> >   * The "fast A20 gate"
> >   */
> > @@ -76,17 +35,6 @@ static void ps2_control_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> >  		ioport__write8(data, 0x02);
> >  }
> >  
> > -static bool ps2_control_a_io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	ps2_control_mmio(vcpu, port, data, size, false, NULL);
> > -	return true;
> > -}
> > -
> > -static struct ioport_operations ps2_control_a_ops = {
> > -	.io_in		= ps2_control_a_io_in,
> > -	.io_out		= dummy_io_out,
> > -};
> > -
> >  void ioport__map_irq(u8 *irq)
> >  {
> >  }
> > @@ -98,75 +46,75 @@ static int ioport__setup_arch(struct kvm *kvm)
> >  	/* Legacy ioport setup */
> >  
> >  	/* 0000 - 001F - DMA1 controller */
> > -	r = ioport__register(kvm, 0x0000, &dummy_read_write_ioport_ops, 32, NULL);
> > +	r = kvm__register_pio(kvm, 0x0000, 32, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 0x0020 - 0x003F - 8259A PIC 1 */
> > -	r = ioport__register(kvm, 0x0020, &dummy_read_write_ioport_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, 0x0020, 2, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
> > -	r = ioport__register(kvm, 0x0040, &dummy_read_write_ioport_ops, 4, NULL);
> > +	r = kvm__register_pio(kvm, 0x0040, 4, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 0092 - PS/2 system control port A */
> > -	r = ioport__register(kvm, 0x0092, &ps2_control_a_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, 0x0092, 1, ps2_control_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 0x00A0 - 0x00AF - 8259A PIC 2 */
> > -	r = ioport__register(kvm, 0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, 0x00A0, 2, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 00C0 - 001F - DMA2 controller */
> > -	r = ioport__register(kvm, 0x00C0, &dummy_read_write_ioport_ops, 32, NULL);
> > +	r = kvm__register_pio(kvm, 0x00c0, 32, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 00E0-00EF are 'motherboard specific' so we use them for our
> >  	   internal debugging purposes.  */
> > -	r = ioport__register(kvm, IOPORT_DBG, &debug_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, IOPORT_DBG, 1, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 00ED - DUMMY PORT FOR DELAY??? */
> > -	r = ioport__register(kvm, 0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, 0x00ed, 1, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 0x00F0 - 0x00FF - Math co-processor */
> > -	r = ioport__register(kvm, 0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, 0x00f0, 2, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 0278-027A - PARALLEL PRINTER PORT (usually LPT1, sometimes LPT2) */
> > -	r = ioport__register(kvm, 0x0278, &dummy_read_write_ioport_ops, 3, NULL);
> > +	r = kvm__register_pio(kvm, 0x0278, 3, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 0378-037A - PARALLEL PRINTER PORT (usually LPT2, sometimes LPT3) */
> > -	r = ioport__register(kvm, 0x0378, &dummy_read_write_ioport_ops, 3, NULL);
> > +	r = kvm__register_pio(kvm, 0x0378, 3, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
> > -	r = ioport__register(kvm, 0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, 0x03d4, 1, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> > -	r = ioport__register(kvm, 0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, 0x03d5, 1, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> > -	r = ioport__register(kvm, 0x402, &seabios_debug_ops, 1, NULL);
> > +	r = kvm__register_pio(kvm, 0x0402, 1, seabios_debug_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> >  	/* 0510 - QEMU BIOS configuration register */
> > -	r = ioport__register(kvm, 0x510, &dummy_read_write_ioport_ops, 2, NULL);
> > +	r = kvm__register_pio(kvm, 0x0510, 2, dummy_mmio, NULL);
> >  	if (r < 0)
> >  		return r;
> >  
> > @@ -176,22 +124,21 @@ dev_base_init(ioport__setup_arch);
> >  
> >  static int ioport__remove_arch(struct kvm *kvm)
> >  {
> > -	ioport__unregister(kvm, 0x510);
> > -	ioport__unregister(kvm, 0x402);
> > -	ioport__unregister(kvm, 0x03D5);
> > -	ioport__unregister(kvm, 0x03D4);
> > -	ioport__unregister(kvm, 0x0378);
> > -	ioport__unregister(kvm, 0x0278);
> > -	ioport__unregister(kvm, 0x00F0);
> > -	ioport__unregister(kvm, 0x00ED);
> > -	ioport__unregister(kvm, IOPORT_DBG);
> > -	ioport__unregister(kvm, 0x00C0);
> > -	ioport__unregister(kvm, 0x00A0);
> > -	ioport__unregister(kvm, 0x0092);
> > -	ioport__unregister(kvm, 0x0040);
> > -	ioport__unregister(kvm, 0x0020);
> > -	ioport__unregister(kvm, 0x0000);
> > -
> > +	kvm__deregister_pio(kvm, 0x510);
> > +	kvm__deregister_pio(kvm, 0x402);
> > +	kvm__deregister_pio(kvm, 0x3d5);
> > +	kvm__deregister_pio(kvm, 0x3d4);
> > +	kvm__deregister_pio(kvm, 0x378);
> > +	kvm__deregister_pio(kvm, 0x278);
> > +	kvm__deregister_pio(kvm, 0x0f0);
> > +	kvm__deregister_pio(kvm, 0x0ed);
> > +	kvm__deregister_pio(kvm, IOPORT_DBG);
> > +	kvm__deregister_pio(kvm, 0x0c0);
> > +	kvm__deregister_pio(kvm, 0x0a0);
> > +	kvm__deregister_pio(kvm, 0x092);
> > +	kvm__deregister_pio(kvm, 0x040);
> > +	kvm__deregister_pio(kvm, 0x020);
> > +	kvm__deregister_pio(kvm, 0x000);
> >  	return 0;
> >  }
> >  dev_base_exit(ioport__remove_arch);  


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

* Re: [PATCH kvmtool 13/21] hw/serial: Refactor trap handler
  2021-02-16 14:22   ` Alexandru Elisei
@ 2021-02-18 14:41     ` Andre Przywara
  2021-02-22 17:40       ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 14:41 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Tue, 16 Feb 2021 14:22:05 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> Patch looks good, nitpicks below.
> 
> On 12/10/20 2:29 PM, Andre Przywara wrote:
> > With the planned retirement of the special ioport emulation code, we
> > need to provide an emulation function compatible with the MMIO prototype.
> >
> > Adjust the trap handler to use that new function, and provide shims to
> > implement the old ioport interface, for now.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/serial.c | 97 +++++++++++++++++++++++++++++++++++------------------
> >  1 file changed, 65 insertions(+), 32 deletions(-)
> >
> > diff --git a/hw/serial.c b/hw/serial.c
> > index b0465d99..2907089c 100644
> > --- a/hw/serial.c
> > +++ b/hw/serial.c
> > @@ -242,36 +242,31 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
> >  	sysrq_pending = sysrq;
> >  }
> >  
> > -static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
> > -			   void *data, int size)
> > +static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> > +			   u16 offset, u8 data)
> >  {
> > -	struct serial8250_device *dev = ioport->priv;
> > -	u16 offset;
> >  	bool ret = true;
> > -	char *addr = data;
> >  
> >  	mutex_lock(&dev->mutex);
> >  
> > -	offset = port - dev->iobase;
> > -
> >  	switch (offset) {
> >  	case UART_TX:
> >  		if (dev->lcr & UART_LCR_DLAB) {
> > -			dev->dll = ioport__read8(data);
> > +			dev->dll = data;
> >  			break;
> >  		}
> >  
> >  		/* Loopback mode */
> >  		if (dev->mcr & UART_MCR_LOOP) {
> >  			if (dev->rxcnt < FIFO_LEN) {
> > -				dev->rxbuf[dev->rxcnt++] = *addr;
> > +				dev->rxbuf[dev->rxcnt++] = data;
> >  				dev->lsr |= UART_LSR_DR;
> >  			}
> >  			break;
> >  		}
> >  
> >  		if (dev->txcnt < FIFO_LEN) {
> > -			dev->txbuf[dev->txcnt++] = *addr;
> > +			dev->txbuf[dev->txcnt++] = data;
> >  			dev->lsr &= ~UART_LSR_TEMT;
> >  			if (dev->txcnt == FIFO_LEN / 2)
> >  				dev->lsr &= ~UART_LSR_THRE;
> > @@ -283,18 +278,18 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
> >  		break;
> >  	case UART_IER:
> >  		if (!(dev->lcr & UART_LCR_DLAB))
> > -			dev->ier = ioport__read8(data) & 0x0f;
> > +			dev->ier = data & 0x0f;
> >  		else
> > -			dev->dlm = ioport__read8(data);
> > +			dev->dlm = data;
> >  		break;
> >  	case UART_FCR:
> > -		dev->fcr = ioport__read8(data);
> > +		dev->fcr = data;
> >  		break;
> >  	case UART_LCR:
> > -		dev->lcr = ioport__read8(data);
> > +		dev->lcr = data;
> >  		break;
> >  	case UART_MCR:
> > -		dev->mcr = ioport__read8(data);
> > +		dev->mcr = data;
> >  		break;
> >  	case UART_LSR:
> >  		/* Factory test */
> > @@ -303,7 +298,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
> >  		/* Not used */
> >  		break;
> >  	case UART_SCR:
> > -		dev->scr = ioport__read8(data);
> > +		dev->scr = data;
> >  		break;
> >  	default:
> >  		ret = false;
> > @@ -336,46 +331,43 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
> >  	}
> >  }
> >  
> > -static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > +static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> > +			  u16 offset, u8 *data)
> >  {
> > -	struct serial8250_device *dev = ioport->priv;
> > -	u16 offset;
> >  	bool ret = true;
> >  
> >  	mutex_lock(&dev->mutex);
> >  
> > -	offset = port - dev->iobase;
> > -
> >  	switch (offset) {
> >  	case UART_RX:
> >  		if (dev->lcr & UART_LCR_DLAB)
> > -			ioport__write8(data, dev->dll);
> > +			*data = dev->dll;
> >  		else
> >  			serial8250_rx(dev, data);
> >  		break;
> >  	case UART_IER:
> >  		if (dev->lcr & UART_LCR_DLAB)
> > -			ioport__write8(data, dev->dlm);
> > +			*data = dev->dlm;
> >  		else
> > -			ioport__write8(data, dev->ier);
> > +			*data = dev->ier;
> >  		break;
> >  	case UART_IIR:
> > -		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
> > +		*data = dev->iir | UART_IIR_TYPE_BITS;
> >  		break;
> >  	case UART_LCR:
> > -		ioport__write8(data, dev->lcr);
> > +		*data = dev->lcr;
> >  		break;
> >  	case UART_MCR:
> > -		ioport__write8(data, dev->mcr);
> > +		*data = dev->mcr;
> >  		break;
> >  	case UART_LSR:
> > -		ioport__write8(data, dev->lsr);
> > +		*data = dev->lsr;
> >  		break;
> >  	case UART_MSR:
> > -		ioport__write8(data, dev->msr);
> > +		*data = dev->msr;
> >  		break;
> >  	case UART_SCR:
> > -		ioport__write8(data, dev->scr);
> > +		*data = dev->scr;
> >  		break;
> >  	default:
> >  		ret = false;
> > @@ -389,6 +381,47 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
> >  	return ret;
> >  }
> >  
> > +static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> > +			    u8 is_write, void *ptr)
> > +{
> > +	struct serial8250_device *dev = ptr;
> > +	u8 value = 0;
> > +
> > +	if (is_write) {
> > +		 value = *data;  
> 
> Extra space before value.
> 
> > +
> > +		serial8250_out(dev, vcpu, addr - dev->iobase, value);
> > +	} else {
> > +		if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
> > +			*data = value;
> > +	}
> > +}
> > +
> > +static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> > +				  u16 port, void *data, int size)
> > +{
> > +	struct serial8250_device *dev = ioport->priv;
> > +	u8 value = ioport__read8(data);
> > +
> > +	serial8250_mmio(vcpu, port, &value, 1, true, dev);
> > +
> > +	return true;
> > +}
> > +
> > +static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> > +				 u16 port, void *data, int size)
> > +{
> > +	struct serial8250_device *dev = ioport->priv;
> > +	u8 value = 0;
> > +
> > +
> > +	serial8250_mmio(vcpu, port, &value, 1, false, dev);
> > +
> > +	ioport__write8(data, value);  
> 
> This is correct, but confusing. You pass the address of a local variable as *data
> to serial8250_mmio, serial8250_mmio conditionally updates the value at data (which
> is &value from here), and then here we update the *data unconditionally. Why not
> pass data directly to serial8250_mmio and skip the local variable? Am I missing
> something?

The idea is to keep the abstraction of ioport__write<x>. I agree this
is somewhat pointless for a single byte write, since the purpose of
those wrappers is to deal with endianness, but it seems nice to use
that anyway, anywhere, in case we need to add something to the wrappers
at some point.
ioport__write8() is a static inline in a header file, so it shouldn't
really hurt, the compiler is able to see through it. The generated code
is almost the same, at least.

Let me know what you think!

Cheers,
Andre

> > +
> > +	return true;
> > +}
> > +
> >  #ifdef CONFIG_HAS_LIBFDT
> >  
> >  char *fdt_stdout_path = NULL;
> > @@ -427,8 +460,8 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> >  #endif
> >  
> >  static struct ioport_operations serial8250_ops = {
> > -	.io_in			= serial8250_in,
> > -	.io_out			= serial8250_out,
> > +	.io_in			= serial8250_ioport_in,
> > +	.io_out			= serial8250_ioport_out,
> >  };
> >  
> >  static int serial8250__device_init(struct kvm *kvm,  


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

* Re: [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler
  2021-02-16 14:47   ` Alexandru Elisei
@ 2021-02-18 15:51     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 15:51 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Tue, 16 Feb 2021 14:47:31 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> Looks good, one nitpick below.
> 
> On 12/10/20 2:29 PM, Andre Przywara wrote:
> > With the planned retirement of the special ioport emulation code, we
> > need to provide an emulation function compatible with the MMIO prototype.
> >
> > Adjust the I/O port trap handler to use that new function, and provide
> > shims to implement the old ioport interface, for now.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  vfio/core.c | 51 ++++++++++++++++++++++++++++++++++++---------------
> >  1 file changed, 36 insertions(+), 15 deletions(-)
> >
> > diff --git a/vfio/core.c b/vfio/core.c
> > index 0b45e78b..f55f1f87 100644
> > --- a/vfio/core.c
> > +++ b/vfio/core.c
> > @@ -81,15 +81,12 @@ out_free_buf:
> >  	return ret;
> >  }
> >  
> > -static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> > -			   u16 port, void *data, int len)
> > +static bool _vfio_ioport_in(struct vfio_region *region, u32 offset,
> > +			    void *data, int len)
> >  {
> > -	u32 val;
> > -	ssize_t nr;
> > -	struct vfio_region *region = ioport->priv;
> >  	struct vfio_device *vdev = region->vdev;
> > -
> > -	u32 offset = port - region->port_base;
> > +	ssize_t nr;
> > +	u32 val;
> >  
> >  	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_READ))
> >  		return false;
> > @@ -97,7 +94,7 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> >  	nr = pread(vdev->fd, &val, len, region->info.offset + offset);
> >  	if (nr != len) {
> >  		vfio_dev_err(vdev, "could not read %d bytes from I/O port 0x%x\n",
> > -			     len, port);
> > +			     len, offset);  
> 
> To keep things functionally identical, shouldn't that be offset +
> region->port_base? I think it's easier to identify the device when we have the PCI
> ioport address.

Yeah, true. Although I think "vfio_dev_err(vdev, ..." already indicates
the device at fault, but indeed the actual ioport address is more
canonical to use.

Thanks,
Andre
 

> 
> Thanks,
> 
> Alex
> 
> >  		return false;
> >  	}
> >  
> > @@ -118,15 +115,13 @@ static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> >  	return true;
> >  }
> >  
> > -static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> > -			    u16 port, void *data, int len)
> > +static bool _vfio_ioport_out(struct vfio_region *region, u32 offset,
> > +			     void *data, int len)
> >  {
> > -	u32 val;
> > -	ssize_t nr;
> > -	struct vfio_region *region = ioport->priv;
> >  	struct vfio_device *vdev = region->vdev;
> > +	ssize_t nr;
> > +	u32 val;
> >  
> > -	u32 offset = port - region->port_base;
> >  
> >  	if (!(region->info.flags & VFIO_REGION_INFO_FLAG_WRITE))
> >  		return false;
> > @@ -148,11 +143,37 @@ static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> >  	nr = pwrite(vdev->fd, &val, len, region->info.offset + offset);
> >  	if (nr != len)
> >  		vfio_dev_err(vdev, "could not write %d bytes to I/O port 0x%x",
> > -			     len, port);
> > +			     len, offset);
> >  
> >  	return nr == len;
> >  }
> >  
> > +static void vfio_ioport_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> > +			     u8 is_write, void *ptr)
> > +{
> > +	struct vfio_region *region = ptr;
> > +	u32 offset = addr - region->port_base;
> > +
> > +	if (is_write)
> > +		_vfio_ioport_out(region, offset, data, len);
> > +	else
> > +		_vfio_ioport_in(region, offset, data, len);
> > +}
> > +
> > +static bool vfio_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> > +			    u16 port, void *data, int len)
> > +{
> > +	vfio_ioport_mmio(vcpu, port, data, len, true, ioport->priv);
> > +	return true;
> > +}
> > +
> > +static bool vfio_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> > +			   u16 port, void *data, int len)
> > +{
> > +	vfio_ioport_mmio(vcpu, port, data, len, false, ioport->priv);
> > +	return true;
> > +}
> > +
> >  static struct ioport_operations vfio_ioport_ops = {
> >  	.io_in	= vfio_ioport_in,
> >  	.io_out	= vfio_ioport_out,  


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

* Re: [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler
  2021-02-16 17:03   ` Alexandru Elisei
@ 2021-02-18 16:13     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 16:13 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Tue, 16 Feb 2021 17:03:04 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> Nitpick below, otherwise looks good.
> 
> On 12/10/20 2:29 PM, Andre Przywara wrote:
> > With the planned retirement of the special ioport emulation code, we
> > need to provide an emulation function compatible with the MMIO prototype.
> >
> > Adjust the existing MMIO callback routine to automatically determine
> > the region this trap came through, and call the existing I/O handlers.
> > Register the ioport region using the new registration function.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  virtio/pci.c | 42 ++++++++++--------------------------------
> >  1 file changed, 10 insertions(+), 32 deletions(-)
> >
> > diff --git a/virtio/pci.c b/virtio/pci.c
> > index 6eea6c68..49d3f4d5 100644
> > --- a/virtio/pci.c
> > +++ b/virtio/pci.c
> > @@ -178,15 +178,6 @@ static bool virtio_pci__data_in(struct kvm_cpu *vcpu, struct virtio_device *vdev
> >  	return ret;
> >  }
> >  
> > -static bool virtio_pci__io_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	struct virtio_device *vdev = ioport->priv;
> > -	struct virtio_pci *vpci = vdev->virtio;
> > -	unsigned long offset = port - virtio_pci__port_addr(vpci);
> > -
> > -	return virtio_pci__data_in(vcpu, vdev, offset, data, size);
> > -}
> > -
> >  static void update_msix_map(struct virtio_pci *vpci,
> >  			    struct msix_table *msix_entry, u32 vecnum)
> >  {
> > @@ -334,20 +325,6 @@ static bool virtio_pci__data_out(struct kvm_cpu *vcpu, struct virtio_device *vde
> >  	return ret;
> >  }
> >  
> > -static bool virtio_pci__io_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> > -{
> > -	struct virtio_device *vdev = ioport->priv;
> > -	struct virtio_pci *vpci = vdev->virtio;
> > -	unsigned long offset = port - virtio_pci__port_addr(vpci);
> > -
> > -	return virtio_pci__data_out(vcpu, vdev, offset, data, size);
> > -}
> > -
> > -static struct ioport_operations virtio_pci__io_ops = {
> > -	.io_in	= virtio_pci__io_in,
> > -	.io_out	= virtio_pci__io_out,
> > -};
> > -
> >  static void virtio_pci__msix_mmio_callback(struct kvm_cpu *vcpu,
> >  					   u64 addr, u8 *data, u32 len,
> >  					   u8 is_write, void *ptr)
> > @@ -455,12 +432,15 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
> >  {
> >  	struct virtio_device *vdev = ptr;
> >  	struct virtio_pci *vpci = vdev->virtio;
> > -	u32 mmio_addr = virtio_pci__mmio_addr(vpci);
> > +	u32 base_addr = virtio_pci__mmio_addr(vpci);
> > +
> > +	if (addr < base_addr || addr >= base_addr + PCI_IO_SIZE)
> > +		base_addr = virtio_pci__port_addr(vpci);  
> 
> There are only two BARs that use this callback, the ioport BAR (BAR0) and the
> memory BAR (BAR1) (MSIX uses a different emulation callback). The condition above
> says that if addr is not inside the region described by the memory BAR, then it's
> an ioport BAR. How about checking explicitly that it is inside the ioport region
> like this (compile tested only), which looks a bit more intuitive for me:

Fair enough.

Cheers,
Andre

> 
> diff --git a/virtio/pci.c b/virtio/pci.c
> index 49d3f4d524b2..4024bcd709cd 100644
> --- a/virtio/pci.c
> +++ b/virtio/pci.c
> @@ -432,10 +432,15 @@ static void virtio_pci__io_mmio_callback(struct kvm_cpu *vcpu,
>  {
>         struct virtio_device *vdev = ptr;
>         struct virtio_pci *vpci = vdev->virtio;
> -       u32 base_addr = virtio_pci__mmio_addr(vpci);
> +       u32 mmio_addr = virtio_pci__mmio_addr(vpci);
> +       u32 ioport_addr = virtio_pci__port_addr(vpci);
> +       u32 base_addr;
>  
> -       if (addr < base_addr || addr >= base_addr + PCI_IO_SIZE)
> -               base_addr = virtio_pci__port_addr(vpci);
> +       if (addr >= ioport_addr &&
> +           addr < ioport_addr + pci__bar_size(&vpci->pci_hdr, 0))
> +               base_addr = ioport_addr;
> +       else
> +               base_addr = mmio_addr;
>  
>         if (!is_write)
>                 virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
> 
> Thanks,
> 
> Alex
> 
> >  
> >  	if (!is_write)
> > -		virtio_pci__data_in(vcpu, vdev, addr - mmio_addr, data, len);
> > +		virtio_pci__data_in(vcpu, vdev, addr - base_addr, data, len);
> >  	else
> > -		virtio_pci__data_out(vcpu, vdev, addr - mmio_addr, data, len);
> > +		virtio_pci__data_out(vcpu, vdev, addr - base_addr, data, len);
> >  }
> >  
> >  static int virtio_pci__bar_activate(struct kvm *kvm,
> > @@ -478,10 +458,8 @@ static int virtio_pci__bar_activate(struct kvm *kvm,
> >  
> >  	switch (bar_num) {
> >  	case 0:
> > -		r = ioport__register(kvm, bar_addr, &virtio_pci__io_ops,
> > -				     bar_size, vdev);
> > -		if (r > 0)
> > -			r = 0;
> > +		r = kvm__register_pio(kvm, bar_addr, bar_size,
> > +				      virtio_pci__io_mmio_callback, vdev);
> >  		break;
> >  	case 1:
> >  		r =  kvm__register_mmio(kvm, bar_addr, bar_size, false,
> > @@ -510,7 +488,7 @@ static int virtio_pci__bar_deactivate(struct kvm *kvm,
> >  
> >  	switch (bar_num) {
> >  	case 0:
> > -		r = ioport__unregister(kvm, bar_addr);
> > +		r = kvm__deregister_pio(kvm, bar_addr);
> >  		break;
> >  	case 1:
> >  	case 2:
> > @@ -625,7 +603,7 @@ int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
> >  	virtio_pci__reset(kvm, vdev);
> >  	kvm__deregister_mmio(kvm, virtio_pci__mmio_addr(vpci));
> >  	kvm__deregister_mmio(kvm, virtio_pci__msix_io_addr(vpci));
> > -	ioport__unregister(kvm, virtio_pci__port_addr(vpci));
> > +	kvm__deregister_pio(kvm, virtio_pci__port_addr(vpci));
> >  
> >  	return 0;
> >  }  


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

* Re: [PATCH kvmtool 19/21] Remove ioport specific routines
  2021-02-17 16:11     ` Alexandru Elisei
@ 2021-02-18 16:34       ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 16:34 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, linux-arm-kernel, Marc Zyngier, kvmarm, kvm

On Wed, 17 Feb 2021 16:11:51 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 2/17/21 3:49 PM, Alexandru Elisei wrote:
> > Hi Andre,
> >
> > On 12/10/20 2:29 PM, Andre Przywara wrote:  
> >> Now that all users of the dedicated ioport trap handler interface are
> >> gone, we can retire the code associated with it.
> >>
> >> This removes ioport.c and ioport.h, along with removing prototypes from
> >> other header files.
> >>
> >> This also transfers the responsibility for port I/O trap handling
> >> entirely into the new routine in mmio.c.
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  Makefile             |   1 -
> >>  include/kvm/ioport.h |  20 -----
> >>  include/kvm/kvm.h    |   2 -
> >>  ioport.c             | 173 -------------------------------------------
> >>  mmio.c               |   2 +-
> >>  5 files changed, 1 insertion(+), 197 deletions(-)
> >>  delete mode 100644 ioport.c
> >>
> >> diff --git a/Makefile b/Makefile
> >> index 35bb1182..94ff5da6 100644
> >> --- a/Makefile
> >> +++ b/Makefile
> >> @@ -56,7 +56,6 @@ OBJS	+= framebuffer.o
> >>  OBJS	+= guest_compat.o
> >>  OBJS	+= hw/rtc.o
> >>  OBJS	+= hw/serial.o
> >> -OBJS	+= ioport.o
> >>  OBJS	+= irq.o
> >>  OBJS	+= kvm-cpu.o
> >>  OBJS	+= kvm.o
> >> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> >> index a61038e2..38636553 100644
> >> --- a/include/kvm/ioport.h
> >> +++ b/include/kvm/ioport.h
> >> @@ -17,28 +17,8 @@
> >>  
> >>  struct kvm;  
> > Looks to me like the above forward declaration can be removed; same for all the
> > includes except linux/byteorder.h, needed for the lexx_to_cpu/cpu_to_lexx
> > functions, and linux/types.h for the uxx typedefs. Otherwise looks good.  
> 
> Actually, ignore the part about removing the includes, it opens a new can of worms
> - byteorder.h doesn't include compiler.h where __always_inline is defined, and
> various files where struct kvm_cpu is used don't include kvm-cpu.h (like pci.c,
> hw/serial.c, etc). The header removal is not trivial and I think it should be part
> of another cleanup patch.

Well, it looks like I can remove some obvious headers like for fdt and
rbtree. Will do that.

Cheers,
Andre

> >
> > Thanks,
> >
> > Alex
> >  
> >>  
> >> -struct ioport {
> >> -	struct rb_int_node		node;
> >> -	struct ioport_operations	*ops;
> >> -	void				*priv;
> >> -	struct device_header		dev_hdr;
> >> -	u32				refcount;
> >> -	bool				remove;
> >> -};
> >> -
> >> -struct ioport_operations {
> >> -	bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> >> -	bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size);
> >> -};
> >> -
> >>  void ioport__map_irq(u8 *irq);
> >>  
> >> -int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> >> -				  int count, void *param);
> >> -int ioport__unregister(struct kvm *kvm, u16 port);
> >> -int ioport__init(struct kvm *kvm);
> >> -int ioport__exit(struct kvm *kvm);
> >> -
> >>  static inline u8 ioport__read8(u8 *data)
> >>  {
> >>  	return *data;
> >> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
> >> index 14f9d58b..e70f8ef6 100644
> >> --- a/include/kvm/kvm.h
> >> +++ b/include/kvm/kvm.h
> >> @@ -119,8 +119,6 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
> >>  void kvm__irq_trigger(struct kvm *kvm, int irq);
> >>  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
> >>  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
> >> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> >> -		      int direction, int size, u32 count);
> >>  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
> >>  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
> >>  		      enum kvm_mem_type type);
> >> diff --git a/ioport.c b/ioport.c
> >> deleted file mode 100644
> >> index 204d8103..00000000
> >> --- a/ioport.c
> >> +++ /dev/null
> >> @@ -1,173 +0,0 @@
> >> -#include "kvm/ioport.h"
> >> -
> >> -#include "kvm/kvm.h"
> >> -#include "kvm/util.h"
> >> -#include "kvm/rbtree-interval.h"
> >> -#include "kvm/mutex.h"
> >> -
> >> -#include <linux/kvm.h>	/* for KVM_EXIT_* */
> >> -#include <linux/types.h>
> >> -
> >> -#include <stdbool.h>
> >> -#include <limits.h>
> >> -#include <stdlib.h>
> >> -#include <stdio.h>
> >> -
> >> -#define ioport_node(n) rb_entry(n, struct ioport, node)
> >> -
> >> -static DEFINE_MUTEX(ioport_lock);
> >> -
> >> -static struct rb_root		ioport_tree = RB_ROOT;
> >> -
> >> -static struct ioport *ioport_search(struct rb_root *root, u64 addr)
> >> -{
> >> -	struct rb_int_node *node;
> >> -
> >> -	node = rb_int_search_single(root, addr);
> >> -	if (node == NULL)
> >> -		return NULL;
> >> -
> >> -	return ioport_node(node);
> >> -}
> >> -
> >> -static int ioport_insert(struct rb_root *root, struct ioport *data)
> >> -{
> >> -	return rb_int_insert(root, &data->node);
> >> -}
> >> -
> >> -static void ioport_remove(struct rb_root *root, struct ioport *data)
> >> -{
> >> -	rb_int_erase(root, &data->node);
> >> -}
> >> -
> >> -static struct ioport *ioport_get(struct rb_root *root, u64 addr)
> >> -{
> >> -	struct ioport *ioport;
> >> -
> >> -	mutex_lock(&ioport_lock);
> >> -	ioport = ioport_search(root, addr);
> >> -	if (ioport)
> >> -		ioport->refcount++;
> >> -	mutex_unlock(&ioport_lock);
> >> -
> >> -	return ioport;
> >> -}
> >> -
> >> -/* Called with ioport_lock held. */
> >> -static void ioport_unregister(struct rb_root *root, struct ioport *data)
> >> -{
> >> -	ioport_remove(root, data);
> >> -	free(data);
> >> -}
> >> -
> >> -static void ioport_put(struct rb_root *root, struct ioport *data)
> >> -{
> >> -	mutex_lock(&ioport_lock);
> >> -	data->refcount--;
> >> -	if (data->remove && data->refcount == 0)
> >> -		ioport_unregister(root, data);
> >> -	mutex_unlock(&ioport_lock);
> >> -}
> >> -
> >> -int ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops, int count, void *param)
> >> -{
> >> -	struct ioport *entry;
> >> -	int r;
> >> -
> >> -	entry = malloc(sizeof(*entry));
> >> -	if (entry == NULL)
> >> -		return -ENOMEM;
> >> -
> >> -	*entry = (struct ioport) {
> >> -		.node		= RB_INT_INIT(port, port + count),
> >> -		.ops		= ops,
> >> -		.priv		= param,
> >> -		/*
> >> -		 * Start from 0 because ioport__unregister() doesn't decrement
> >> -		 * the reference count.
> >> -		 */
> >> -		.refcount	= 0,
> >> -		.remove		= false,
> >> -	};
> >> -
> >> -	mutex_lock(&ioport_lock);
> >> -	r = ioport_insert(&ioport_tree, entry);
> >> -	if (r < 0)
> >> -		goto out_free;
> >> -	mutex_unlock(&ioport_lock);
> >> -
> >> -	return port;
> >> -
> >> -out_free:
> >> -	free(entry);
> >> -	mutex_unlock(&ioport_lock);
> >> -	return r;
> >> -}
> >> -
> >> -int ioport__unregister(struct kvm *kvm, u16 port)
> >> -{
> >> -	struct ioport *entry;
> >> -
> >> -	mutex_lock(&ioport_lock);
> >> -	entry = ioport_search(&ioport_tree, port);
> >> -	if (!entry) {
> >> -		mutex_unlock(&ioport_lock);
> >> -		return -ENOENT;
> >> -	}
> >> -	/* The same reasoning from kvm__deregister_mmio() applies. */
> >> -	if (entry->refcount == 0)
> >> -		ioport_unregister(&ioport_tree, entry);
> >> -	else
> >> -		entry->remove = true;
> >> -	mutex_unlock(&ioport_lock);
> >> -
> >> -	return 0;
> >> -}
> >> -
> >> -static const char *to_direction(int direction)
> >> -{
> >> -	if (direction == KVM_EXIT_IO_IN)
> >> -		return "IN";
> >> -	else
> >> -		return "OUT";
> >> -}
> >> -
> >> -static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
> >> -{
> >> -	fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
> >> -}
> >> -
> >> -bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count)
> >> -{
> >> -	struct ioport_operations *ops;
> >> -	bool ret = false;
> >> -	struct ioport *entry;
> >> -	void *ptr = data;
> >> -	struct kvm *kvm = vcpu->kvm;
> >> -
> >> -	entry = ioport_get(&ioport_tree, port);
> >> -	if (!entry)
> >> -		return kvm__emulate_pio(vcpu, port, data, direction,
> >> -					size, count);
> >> -
> >> -	ops	= entry->ops;
> >> -
> >> -	while (count--) {
> >> -		if (direction == KVM_EXIT_IO_IN && ops->io_in)
> >> -				ret = ops->io_in(entry, vcpu, port, ptr, size);
> >> -		else if (direction == KVM_EXIT_IO_OUT && ops->io_out)
> >> -				ret = ops->io_out(entry, vcpu, port, ptr, size);
> >> -
> >> -		ptr += size;
> >> -	}
> >> -
> >> -	ioport_put(&ioport_tree, entry);
> >> -
> >> -	if (ret)
> >> -		return true;
> >> -
> >> -	if (kvm->cfg.ioport_debug)
> >> -		ioport_error(port, data, direction, size, count);
> >> -
> >> -	return !kvm->cfg.ioport_debug;
> >> -}
> >> diff --git a/mmio.c b/mmio.c
> >> index 4cce1901..5249af39 100644
> >> --- a/mmio.c
> >> +++ b/mmio.c
> >> @@ -206,7 +206,7 @@ out:
> >>  	return true;
> >>  }
> >>  
> >> -bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
> >> +bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data,
> >>  		     int direction, int size, u32 count)
> >>  {
> >>  	struct mmio_mapping *mmio;  
> > _______________________________________________
> > kvmarm mailing list
> > kvmarm@lists.cs.columbia.edu
> > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm  


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

* Re: [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses
  2021-02-18 12:18     ` Alexandru Elisei
@ 2021-02-18 16:38       ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 16:38 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, linux-arm-kernel, Marc Zyngier, kvmarm, kvm

On Thu, 18 Feb 2021 12:18:38 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 2/17/21 4:48 PM, Alexandru Elisei wrote:
> > Hi Andre,
> >
> > On 12/10/20 2:29 PM, Andre Przywara wrote:  
> >> Using the UART devices at their legacy I/O addresses as set by IBM in
> >> 1981 was a kludge we used for simplicity on ARM platforms as well.
> >> However this imposes problems due to their missing alignment and overlap
> >> with the PCI I/O address space.
> >>
> >> Now that we can switch a device easily between using ioports and MMIO,
> >> let's move the UARTs out of the first 4K of memory on ARM platforms.
> >>
> >> That should be transparent for well behaved guests, since the change is
> >> naturally reflected in the device tree. Even "earlycon" keeps working,
> >> as the stdout-path property is adjusted automatically.
> >>
> >> People providing direct earlycon parameters via the command line need to
> >> adjust it to: "earlycon=uart,mmio,0x1000000".
> >>
> >> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >> ---
> >>  hw/serial.c | 52 ++++++++++++++++++++++++++++++++++++----------------
> >>  1 file changed, 36 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/hw/serial.c b/hw/serial.c
> >> index d840eebc..00fb3aa8 100644
> >> --- a/hw/serial.c
> >> +++ b/hw/serial.c
> >> @@ -13,6 +13,24 @@
> >>  
> >>  #include <pthread.h>
> >>  
> >> +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> >> +#define serial_iobase(nr)	(0x1000000 + (nr) * 0x1000)
> >> +#define serial_irq(nr)		(32 + (nr))
> >> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_MMIO
> >> +#else
> >> +#define serial_iobase_0		0x3f8
> >> +#define serial_iobase_1		0x2f8
> >> +#define serial_iobase_2		0x3e8
> >> +#define serial_iobase_3		0x2e8
> >> +#define serial_irq_0		4
> >> +#define serial_irq_1		3
> >> +#define serial_irq_2		4
> >> +#define serial_irq_3		3  
> > Nitpick: serial_iobase_* and serial_irq_* could be changed to have two leading
> > underscores, to stress the fact that they are helpers for serial_iobase() and
> > serial_irq() and are not meant to be used by themselves. But that's just personal
> > preference, otherwise the patch looks really nice and clean:
> >
> > Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>  
> 
> I gave it more thought and I think I spoke too soon. I think it would be good to
> document in the commit message how you came to the base MMIO address and size
> (even if it was just a nice looking number). Also, the CFI flash device has its
> memory range described in the memory layout for the architecture, in
> arm/include/arm-common/kvm-arch.h. I think it would be a good idea to put the
> serial region there, to prevent regressions in the future.

Yes, that's very true, the memory map should be described in one place
only. Will try to do that.


> 
> I did the math to make sure there's no overlap with the ioport region (16M >> 16K)
> or the flash region (16M + 0x4000 < 32M). I also tested the changes with a kernel
> with 4K and 64K pages (I can't access any hardware with 16K pages at the moment),
> and everything worked as expected.

Thanks!
Andre

> >> +#define serial_iobase(nr)	serial_iobase_##nr
> >> +#define serial_irq(nr)		serial_irq_##nr
> >> +#define SERIAL8250_BUS_TYPE	DEVICE_BUS_IOPORT
> >> +#endif
> >> +
> >>  /*
> >>   * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
> >>   * expects that for autodetection.
> >> @@ -27,7 +45,7 @@ struct serial8250_device {
> >>  	struct mutex		mutex;
> >>  	u8			id;
> >>  
> >> -	u16			iobase;
> >> +	u32			iobase;
> >>  	u8			irq;
> >>  	u8			irq_state;
> >>  	int			txcnt;
> >> @@ -65,56 +83,56 @@ static struct serial8250_device devices[] = {
> >>  	/* ttyS0 */
> >>  	[0]	= {
> >>  		.dev_hdr = {
> >> -			.bus_type	= DEVICE_BUS_IOPORT,
> >> +			.bus_type	= SERIAL8250_BUS_TYPE,
> >>  			.data		= serial8250_generate_fdt_node,
> >>  		},
> >>  		.mutex			= MUTEX_INITIALIZER,
> >>  
> >>  		.id			= 0,
> >> -		.iobase			= 0x3f8,
> >> -		.irq			= 4,
> >> +		.iobase			= serial_iobase(0),
> >> +		.irq			= serial_irq(0),
> >>  
> >>  		SERIAL_REGS_SETTING
> >>  	},
> >>  	/* ttyS1 */
> >>  	[1]	= {
> >>  		.dev_hdr = {
> >> -			.bus_type	= DEVICE_BUS_IOPORT,
> >> +			.bus_type	= SERIAL8250_BUS_TYPE,
> >>  			.data		= serial8250_generate_fdt_node,
> >>  		},
> >>  		.mutex			= MUTEX_INITIALIZER,
> >>  
> >>  		.id			= 1,
> >> -		.iobase			= 0x2f8,
> >> -		.irq			= 3,
> >> +		.iobase			= serial_iobase(1),
> >> +		.irq			= serial_irq(1),
> >>  
> >>  		SERIAL_REGS_SETTING
> >>  	},
> >>  	/* ttyS2 */
> >>  	[2]	= {
> >>  		.dev_hdr = {
> >> -			.bus_type	= DEVICE_BUS_IOPORT,
> >> +			.bus_type	= SERIAL8250_BUS_TYPE,
> >>  			.data		= serial8250_generate_fdt_node,
> >>  		},
> >>  		.mutex			= MUTEX_INITIALIZER,
> >>  
> >>  		.id			= 2,
> >> -		.iobase			= 0x3e8,
> >> -		.irq			= 4,
> >> +		.iobase			= serial_iobase(2),
> >> +		.irq			= serial_irq(2),
> >>  
> >>  		SERIAL_REGS_SETTING
> >>  	},
> >>  	/* ttyS3 */
> >>  	[3]	= {
> >>  		.dev_hdr = {
> >> -			.bus_type	= DEVICE_BUS_IOPORT,
> >> +			.bus_type	= SERIAL8250_BUS_TYPE,
> >>  			.data		= serial8250_generate_fdt_node,
> >>  		},
> >>  		.mutex			= MUTEX_INITIALIZER,
> >>  
> >>  		.id			= 3,
> >> -		.iobase			= 0x2e8,
> >> -		.irq			= 3,
> >> +		.iobase			= serial_iobase(3),
> >> +		.irq			= serial_irq(3),
> >>  
> >>  		SERIAL_REGS_SETTING
> >>  	},
> >> @@ -444,7 +462,8 @@ static int serial8250__device_init(struct kvm *kvm,
> >>  		return r;
> >>  
> >>  	ioport__map_irq(&dev->irq);
> >> -	r = kvm__register_pio(kvm, dev->iobase, 8, serial8250_mmio, dev);
> >> +	r = kvm__register_iotrap(kvm, dev->iobase, 8, serial8250_mmio, dev,
> >> +				 SERIAL8250_BUS_TYPE);
> >>  
> >>  	return r;
> >>  }
> >> @@ -467,7 +486,7 @@ cleanup:
> >>  	for (j = 0; j <= i; j++) {
> >>  		struct serial8250_device *dev = &devices[j];
> >>  
> >> -		kvm__deregister_pio(kvm, dev->iobase);
> >> +		kvm__deregister_iotrap(kvm, dev->iobase, SERIAL8250_BUS_TYPE);
> >>  		device__unregister(&dev->dev_hdr);
> >>  	}
> >>  
> >> @@ -483,7 +502,8 @@ int serial8250__exit(struct kvm *kvm)
> >>  	for (i = 0; i < ARRAY_SIZE(devices); i++) {
> >>  		struct serial8250_device *dev = &devices[i];
> >>  
> >> -		r = kvm__deregister_pio(kvm, dev->iobase);
> >> +		r = kvm__deregister_iotrap(kvm, dev->iobase,
> >> +					   SERIAL8250_BUS_TYPE);
> >>  		if (r < 0)
> >>  			return r;
> >>  		device__unregister(&dev->dev_hdr);  
> > _______________________________________________
> > kvmarm mailing list
> > kvmarm@lists.cs.columbia.edu
> > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm  


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

* Re: [PATCH kvmtool 21/21] hw/rtc: ARM/arm64: Use MMIO at higher addresses
  2021-02-18 13:33   ` Alexandru Elisei
@ 2021-02-18 16:41     ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-18 16:41 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Thu, 18 Feb 2021 13:33:15 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

> Hi Andre,
> 
> On 12/10/20 2:29 PM, Andre Przywara wrote:
> > Using the RTC device at its legacy I/O address as set by IBM in 1981
> > was a kludge we used for simplicity on ARM platforms as well.
> > However this imposes problems due to their missing alignment and overlap
> > with the PCI I/O address space.
> >
> > Now that we can switch a device easily between using ioports and
> > MMIO, let's move the RTC out of the first 4K of memory on ARM platforms.
> >
> > That should be transparent for well behaved guests, since the change is
> > naturally reflected in the device tree.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > ---
> >  hw/rtc.c | 24 ++++++++++++++++--------
> >  1 file changed, 16 insertions(+), 8 deletions(-)
> >
> > diff --git a/hw/rtc.c b/hw/rtc.c
> > index ee4c9102..bdb88f0f 100644
> > --- a/hw/rtc.c
> > +++ b/hw/rtc.c
> > @@ -5,6 +5,15 @@
> >  
> >  #include <time.h>
> >  
> > +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
> > +#define RTC_BUS_TYPE		DEVICE_BUS_MMIO
> > +#define RTC_BASE_ADDRESS	0x1010000  
> 
> This looks correct, the base address is the serial base address + 64k, so they
> don't overlap, and it doesn't overlap with the flash memory either. Same comment
> as for the serial, I think the reason for choosing this address should be
> mentioned, and the region should be put in the arch memory layout file. Other than
> that, the patch looks good.

Yep, will do!

Thanks,
Andre

> 
> > +#else
> > +/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> > +#define RTC_BUS_TYPE		DEVICE_BUS_IOPORT
> > +#define RTC_BASE_ADDRESS	0x70
> > +#endif
> > +
> >  /*
> >   * MC146818 RTC registers
> >   */
> > @@ -49,7 +58,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> >  	time_t ti;
> >  
> >  	if (is_write) {
> > -		if (addr == 0x70) {	/* index register */
> > +		if (addr == RTC_BASE_ADDRESS) {	/* index register */
> >  			u8 value = ioport__read8(data);
> >  
> >  			vcpu->kvm->nmi_disabled	= value & (1UL << 7);
> > @@ -70,7 +79,7 @@ static void cmos_ram_io(struct kvm_cpu *vcpu, u64 addr, u8 *data,
> >  		return;
> >  	}
> >  
> > -	if (addr == 0x70)
> > +	if (addr == RTC_BASE_ADDRESS)	/* index register is write-only */
> >  		return;
> >  
> >  	time(&ti);
> > @@ -127,7 +136,7 @@ static void generate_rtc_fdt_node(void *fdt,
> >  							    u8 irq,
> >  							    enum irq_type))
> >  {
> > -	u64 reg_prop[2] = { cpu_to_fdt64(0x70), cpu_to_fdt64(2) };
> > +	u64 reg_prop[2] = { cpu_to_fdt64(RTC_BASE_ADDRESS), cpu_to_fdt64(2) };
> >  
> >  	_FDT(fdt_begin_node(fdt, "rtc"));
> >  	_FDT(fdt_property_string(fdt, "compatible", "motorola,mc146818"));
> > @@ -139,7 +148,7 @@ static void generate_rtc_fdt_node(void *fdt,
> >  #endif
> >  
> >  struct device_header rtc_dev_hdr = {
> > -	.bus_type = DEVICE_BUS_IOPORT,
> > +	.bus_type = RTC_BUS_TYPE,
> >  	.data = generate_rtc_fdt_node,
> >  };
> >  
> > @@ -151,8 +160,8 @@ int rtc__init(struct kvm *kvm)
> >  	if (r < 0)
> >  		return r;
> >  
> > -	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> > -	r = kvm__register_pio(kvm, 0x0070, 2, cmos_ram_io, NULL);
> > +	r = kvm__register_iotrap(kvm, RTC_BASE_ADDRESS, 2, cmos_ram_io, NULL,
> > +				 RTC_BUS_TYPE);
> >  	if (r < 0)
> >  		goto out_device;
> >  
> > @@ -170,8 +179,7 @@ dev_init(rtc__init);
> >  
> >  int rtc__exit(struct kvm *kvm)
> >  {
> > -	/* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
> > -	kvm__deregister_pio(kvm, 0x0070);
> > +	kvm__deregister_iotrap(kvm, RTC_BASE_ADDRESS, RTC_BUS_TYPE);
> >  
> >  	return 0;
> >  }  


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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2021-02-17 16:46         ` Andre Przywara
@ 2021-02-22 10:23           ` Andre Przywara
  2021-02-22 15:01             ` Alexandru Elisei
  0 siblings, 1 reply; 72+ messages in thread
From: Andre Przywara @ 2021-02-22 10:23 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Wed, 17 Feb 2021 16:46:47 +0000
Andre Przywara <andre.przywara@arm.com> wrote:

> On Thu, 11 Feb 2021 17:32:01 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> 
> Hi,
> 
> > On 2/11/21 5:16 PM, Andre Przywara wrote:  
> > > On Wed, 10 Feb 2021 17:44:59 +0000
> > > Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> > >
> > > Hi Alex,
> > >    
> > >> On 12/10/20 2:28 PM, Andre Przywara wrote:    
> > >>> Since x86 had a special need for registering tons of special I/O ports,
> > >>> we had an ioport__setup_arch() callback, to allow each architecture
> > >>> to do the same. As it turns out no one uses it beside x86, so we remove
> > >>> that unnecessary abstraction.
> > >>>
> > >>> The generic function was registered via a device_base_init() call, so
> > >>> we just do the same for the x86 specific function only, and can remove
> > >>> the unneeded ioport__setup_arch().
> > >>>
> > >>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > >>> ---
> > >>>  arm/ioport.c         |  5 -----
> > >>>  include/kvm/ioport.h |  1 -
> > >>>  ioport.c             | 28 ----------------------------
> > >>>  mips/kvm.c           |  5 -----
> > >>>  powerpc/ioport.c     |  6 ------
> > >>>  x86/ioport.c         | 25 ++++++++++++++++++++++++-
> > >>>  6 files changed, 24 insertions(+), 46 deletions(-)
> > >>>
> > >>> diff --git a/arm/ioport.c b/arm/ioport.c
> > >>> index 2f0feb9a..24092c9d 100644
> > >>> --- a/arm/ioport.c
> > >>> +++ b/arm/ioport.c
> > >>> @@ -1,11 +1,6 @@
> > >>>  #include "kvm/ioport.h"
> > >>>  #include "kvm/irq.h"
> > >>>  
> > >>> -int ioport__setup_arch(struct kvm *kvm)
> > >>> -{
> > >>> -	return 0;
> > >>> -}
> > >>> -
> > >>>  void ioport__map_irq(u8 *irq)
> > >>>  {
> > >>>  	*irq = irq__alloc_line();
> > >>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
> > >>> index 039633f7..d0213541 100644
> > >>> --- a/include/kvm/ioport.h
> > >>> +++ b/include/kvm/ioport.h
> > >>> @@ -35,7 +35,6 @@ struct ioport_operations {
> > >>>  							    enum irq_type));
> > >>>  };
> > >>>  
> > >>> -int ioport__setup_arch(struct kvm *kvm);
> > >>>  void ioport__map_irq(u8 *irq);
> > >>>  
> > >>>  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
> > >>> diff --git a/ioport.c b/ioport.c
> > >>> index 844a832d..667e8386 100644
> > >>> --- a/ioport.c
> > >>> +++ b/ioport.c
> > >>> @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
> > >>>  	return 0;
> > >>>  }
> > >>>  
> > >>> -static void ioport__unregister_all(void)
> > >>> -{
> > >>> -	struct ioport *entry;
> > >>> -	struct rb_node *rb;
> > >>> -	struct rb_int_node *rb_node;
> > >>> -
> > >>> -	rb = rb_first(&ioport_tree);
> > >>> -	while (rb) {
> > >>> -		rb_node = rb_int(rb);
> > >>> -		entry = ioport_node(rb_node);
> > >>> -		ioport_unregister(&ioport_tree, entry);
> > >>> -		rb = rb_first(&ioport_tree);
> > >>> -	}
> > >>> -}      
> > >> I get the impression this is a rebasing artifact. The commit message doesn't
> > >> mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
> > >> far as I can tell it's still needed because there are places other than
> > >> ioport__setup_arch() from where ioport__register() is called.    
> > > I agree that the commit message is a bit thin on this fact, but the
> > > functionality of ioport__unregister_all() is now in
> > > x86/ioport.c:ioport__remove_arch(). I think removing ioport__init()
> > > without removing ioport__exit() as well would look very weird, if not
> > > hackish.    
> > 
> > Not necessarily. ioport__unregister_all() removes the ioports added by
> > x86/ioport.c::ioport__setup_arch(), *plus* ioports added by different devices,
> > like serial, rtc, virtio-pci and vfio-pci (which are used by arm/arm64).  
> 
> Right, indeed. Not that it really matters, since we are about to exit
> anyway, but it looks indeed I need to move this to a generic teardown
> method, or actually just keep that part here in this file.
> 
> Will give this a try.

Well, now having a closer look I needed to remove this from here,
because this whole file will go away.
To keep the current functionality, we would need to add it to mmio.c,
and interestingly we don't do any kind of similar cleanup there for the
MMIO regions (probably this is kvmtool exiting anyway, see above).

I will see if I can introduce it there, for good measure.

Cheers,
Andre


> 
> Thanks!
> Andre
> 
> > >
> > > I can amend the commit message to mention this, or is there anything
> > > else I missed?
> > >
> > > Cheers,
> > > Andre
> > >    
> > >>> -
> > >>>  static const char *to_direction(int direction)
> > >>>  {
> > >>>  	if (direction == KVM_EXIT_IO_IN)
> > >>> @@ -220,16 +205,3 @@ out:
> > >>>  
> > >>>  	return !kvm->cfg.ioport_debug;
> > >>>  }
> > >>> -
> > >>> -int ioport__init(struct kvm *kvm)
> > >>> -{
> > >>> -	return ioport__setup_arch(kvm);
> > >>> -}
> > >>> -dev_base_init(ioport__init);
> > >>> -
> > >>> -int ioport__exit(struct kvm *kvm)
> > >>> -{
> > >>> -	ioport__unregister_all();
> > >>> -	return 0;
> > >>> -}
> > >>> -dev_base_exit(ioport__exit);
> > >>> diff --git a/mips/kvm.c b/mips/kvm.c
> > >>> index 26355930..e110e5d5 100644
> > >>> --- a/mips/kvm.c
> > >>> +++ b/mips/kvm.c
> > >>> @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
> > >>>  		die_perror("KVM_IRQ_LINE ioctl");
> > >>>  }
> > >>>  
> > >>> -int ioport__setup_arch(struct kvm *kvm)
> > >>> -{
> > >>> -	return 0;
> > >>> -}
> > >>> -
> > >>>  bool kvm__arch_cpu_supports_vm(void)
> > >>>  {
> > >>>  	return true;
> > >>> diff --git a/powerpc/ioport.c b/powerpc/ioport.c
> > >>> index 0c188b61..a5cff4ee 100644
> > >>> --- a/powerpc/ioport.c
> > >>> +++ b/powerpc/ioport.c
> > >>> @@ -12,12 +12,6 @@
> > >>>  
> > >>>  #include <stdlib.h>
> > >>>  
> > >>> -int ioport__setup_arch(struct kvm *kvm)
> > >>> -{
> > >>> -	/* PPC has no legacy ioports to set up */
> > >>> -	return 0;
> > >>> -}
> > >>> -
> > >>>  void ioport__map_irq(u8 *irq)
> > >>>  {
> > >>>  }
> > >>> diff --git a/x86/ioport.c b/x86/ioport.c
> > >>> index 7ad7b8f3..8c5c7699 100644
> > >>> --- a/x86/ioport.c
> > >>> +++ b/x86/ioport.c
> > >>> @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
> > >>>  {
> > >>>  }
> > >>>  
> > >>> -int ioport__setup_arch(struct kvm *kvm)
> > >>> +static int ioport__setup_arch(struct kvm *kvm)
> > >>>  {
> > >>>  	int r;
> > >>>  
> > >>> @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
> > >>>  
> > >>>  	return 0;
> > >>>  }
> > >>> +dev_base_init(ioport__setup_arch);
> > >>> +
> > >>> +static int ioport__remove_arch(struct kvm *kvm)
> > >>> +{
> > >>> +	ioport__unregister(kvm, 0x510);
> > >>> +	ioport__unregister(kvm, 0x402);
> > >>> +	ioport__unregister(kvm, 0x03D5);
> > >>> +	ioport__unregister(kvm, 0x03D4);
> > >>> +	ioport__unregister(kvm, 0x0378);
> > >>> +	ioport__unregister(kvm, 0x0278);
> > >>> +	ioport__unregister(kvm, 0x00F0);
> > >>> +	ioport__unregister(kvm, 0x00ED);
> > >>> +	ioport__unregister(kvm, IOPORT_DBG);
> > >>> +	ioport__unregister(kvm, 0x00C0);
> > >>> +	ioport__unregister(kvm, 0x00A0);
> > >>> +	ioport__unregister(kvm, 0x0092);
> > >>> +	ioport__unregister(kvm, 0x0040);
> > >>> +	ioport__unregister(kvm, 0x0020);
> > >>> +	ioport__unregister(kvm, 0x0000);
> > >>> +
> > >>> +	return 0;
> > >>> +}
> > >>> +dev_base_exit(ioport__remove_arch);      
> 


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

* Re: [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch()
  2021-02-22 10:23           ` Andre Przywara
@ 2021-02-22 15:01             ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-22 15:01 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/22/21 10:23 AM, Andre Przywara wrote:
> On Wed, 17 Feb 2021 16:46:47 +0000
> Andre Przywara <andre.przywara@arm.com> wrote:
>
>> On Thu, 11 Feb 2021 17:32:01 +0000
>> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>>
>> Hi,
>>
>>> On 2/11/21 5:16 PM, Andre Przywara wrote:  
>>>> On Wed, 10 Feb 2021 17:44:59 +0000
>>>> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>>>>
>>>> Hi Alex,
>>>>    
>>>>> On 12/10/20 2:28 PM, Andre Przywara wrote:    
>>>>>> Since x86 had a special need for registering tons of special I/O ports,
>>>>>> we had an ioport__setup_arch() callback, to allow each architecture
>>>>>> to do the same. As it turns out no one uses it beside x86, so we remove
>>>>>> that unnecessary abstraction.
>>>>>>
>>>>>> The generic function was registered via a device_base_init() call, so
>>>>>> we just do the same for the x86 specific function only, and can remove
>>>>>> the unneeded ioport__setup_arch().
>>>>>>
>>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>>> ---
>>>>>>  arm/ioport.c         |  5 -----
>>>>>>  include/kvm/ioport.h |  1 -
>>>>>>  ioport.c             | 28 ----------------------------
>>>>>>  mips/kvm.c           |  5 -----
>>>>>>  powerpc/ioport.c     |  6 ------
>>>>>>  x86/ioport.c         | 25 ++++++++++++++++++++++++-
>>>>>>  6 files changed, 24 insertions(+), 46 deletions(-)
>>>>>>
>>>>>> diff --git a/arm/ioport.c b/arm/ioport.c
>>>>>> index 2f0feb9a..24092c9d 100644
>>>>>> --- a/arm/ioport.c
>>>>>> +++ b/arm/ioport.c
>>>>>> @@ -1,11 +1,6 @@
>>>>>>  #include "kvm/ioport.h"
>>>>>>  #include "kvm/irq.h"
>>>>>>  
>>>>>> -int ioport__setup_arch(struct kvm *kvm)
>>>>>> -{
>>>>>> -	return 0;
>>>>>> -}
>>>>>> -
>>>>>>  void ioport__map_irq(u8 *irq)
>>>>>>  {
>>>>>>  	*irq = irq__alloc_line();
>>>>>> diff --git a/include/kvm/ioport.h b/include/kvm/ioport.h
>>>>>> index 039633f7..d0213541 100644
>>>>>> --- a/include/kvm/ioport.h
>>>>>> +++ b/include/kvm/ioport.h
>>>>>> @@ -35,7 +35,6 @@ struct ioport_operations {
>>>>>>  							    enum irq_type));
>>>>>>  };
>>>>>>  
>>>>>> -int ioport__setup_arch(struct kvm *kvm);
>>>>>>  void ioport__map_irq(u8 *irq);
>>>>>>  
>>>>>>  int __must_check ioport__register(struct kvm *kvm, u16 port, struct ioport_operations *ops,
>>>>>> diff --git a/ioport.c b/ioport.c
>>>>>> index 844a832d..667e8386 100644
>>>>>> --- a/ioport.c
>>>>>> +++ b/ioport.c
>>>>>> @@ -158,21 +158,6 @@ int ioport__unregister(struct kvm *kvm, u16 port)
>>>>>>  	return 0;
>>>>>>  }
>>>>>>  
>>>>>> -static void ioport__unregister_all(void)
>>>>>> -{
>>>>>> -	struct ioport *entry;
>>>>>> -	struct rb_node *rb;
>>>>>> -	struct rb_int_node *rb_node;
>>>>>> -
>>>>>> -	rb = rb_first(&ioport_tree);
>>>>>> -	while (rb) {
>>>>>> -		rb_node = rb_int(rb);
>>>>>> -		entry = ioport_node(rb_node);
>>>>>> -		ioport_unregister(&ioport_tree, entry);
>>>>>> -		rb = rb_first(&ioport_tree);
>>>>>> -	}
>>>>>> -}      
>>>>> I get the impression this is a rebasing artifact. The commit message doesn't
>>>>> mention anything about removing ioport__exit() -> ioport__unregister_all(), and as
>>>>> far as I can tell it's still needed because there are places other than
>>>>> ioport__setup_arch() from where ioport__register() is called.    
>>>> I agree that the commit message is a bit thin on this fact, but the
>>>> functionality of ioport__unregister_all() is now in
>>>> x86/ioport.c:ioport__remove_arch(). I think removing ioport__init()
>>>> without removing ioport__exit() as well would look very weird, if not
>>>> hackish.    
>>> Not necessarily. ioport__unregister_all() removes the ioports added by
>>> x86/ioport.c::ioport__setup_arch(), *plus* ioports added by different devices,
>>> like serial, rtc, virtio-pci and vfio-pci (which are used by arm/arm64).  
>> Right, indeed. Not that it really matters, since we are about to exit
>> anyway, but it looks indeed I need to move this to a generic teardown
>> method, or actually just keep that part here in this file.
>>
>> Will give this a try.
> Well, now having a closer look I needed to remove this from here,
> because this whole file will go away.
> To keep the current functionality, we would need to add it to mmio.c,
> and interestingly we don't do any kind of similar cleanup there for the
> MMIO regions (probably this is kvmtool exiting anyway, see above).

This is a very good point. If the MMIO emulation doesn't unregister each MMIO
region before exiting (and has never done that since it was implemented), then I
don't think there's a reason that we should add it now. After all, kvmtool will
terminate after calling dev_base_exit destructors, which will take care of
deallocating the entire process memory.

Thanks,

Alex

>
> I will see if I can introduce it there, for good measure.
>
> Cheers,
> Andre
>
>
>> Thanks!
>> Andre
>>
>>>> I can amend the commit message to mention this, or is there anything
>>>> else I missed?
>>>>
>>>> Cheers,
>>>> Andre
>>>>    
>>>>>> -
>>>>>>  static const char *to_direction(int direction)
>>>>>>  {
>>>>>>  	if (direction == KVM_EXIT_IO_IN)
>>>>>> @@ -220,16 +205,3 @@ out:
>>>>>>  
>>>>>>  	return !kvm->cfg.ioport_debug;
>>>>>>  }
>>>>>> -
>>>>>> -int ioport__init(struct kvm *kvm)
>>>>>> -{
>>>>>> -	return ioport__setup_arch(kvm);
>>>>>> -}
>>>>>> -dev_base_init(ioport__init);
>>>>>> -
>>>>>> -int ioport__exit(struct kvm *kvm)
>>>>>> -{
>>>>>> -	ioport__unregister_all();
>>>>>> -	return 0;
>>>>>> -}
>>>>>> -dev_base_exit(ioport__exit);
>>>>>> diff --git a/mips/kvm.c b/mips/kvm.c
>>>>>> index 26355930..e110e5d5 100644
>>>>>> --- a/mips/kvm.c
>>>>>> +++ b/mips/kvm.c
>>>>>> @@ -100,11 +100,6 @@ void kvm__irq_trigger(struct kvm *kvm, int irq)
>>>>>>  		die_perror("KVM_IRQ_LINE ioctl");
>>>>>>  }
>>>>>>  
>>>>>> -int ioport__setup_arch(struct kvm *kvm)
>>>>>> -{
>>>>>> -	return 0;
>>>>>> -}
>>>>>> -
>>>>>>  bool kvm__arch_cpu_supports_vm(void)
>>>>>>  {
>>>>>>  	return true;
>>>>>> diff --git a/powerpc/ioport.c b/powerpc/ioport.c
>>>>>> index 0c188b61..a5cff4ee 100644
>>>>>> --- a/powerpc/ioport.c
>>>>>> +++ b/powerpc/ioport.c
>>>>>> @@ -12,12 +12,6 @@
>>>>>>  
>>>>>>  #include <stdlib.h>
>>>>>>  
>>>>>> -int ioport__setup_arch(struct kvm *kvm)
>>>>>> -{
>>>>>> -	/* PPC has no legacy ioports to set up */
>>>>>> -	return 0;
>>>>>> -}
>>>>>> -
>>>>>>  void ioport__map_irq(u8 *irq)
>>>>>>  {
>>>>>>  }
>>>>>> diff --git a/x86/ioport.c b/x86/ioport.c
>>>>>> index 7ad7b8f3..8c5c7699 100644
>>>>>> --- a/x86/ioport.c
>>>>>> +++ b/x86/ioport.c
>>>>>> @@ -69,7 +69,7 @@ void ioport__map_irq(u8 *irq)
>>>>>>  {
>>>>>>  }
>>>>>>  
>>>>>> -int ioport__setup_arch(struct kvm *kvm)
>>>>>> +static int ioport__setup_arch(struct kvm *kvm)
>>>>>>  {
>>>>>>  	int r;
>>>>>>  
>>>>>> @@ -150,3 +150,26 @@ int ioport__setup_arch(struct kvm *kvm)
>>>>>>  
>>>>>>  	return 0;
>>>>>>  }
>>>>>> +dev_base_init(ioport__setup_arch);
>>>>>> +
>>>>>> +static int ioport__remove_arch(struct kvm *kvm)
>>>>>> +{
>>>>>> +	ioport__unregister(kvm, 0x510);
>>>>>> +	ioport__unregister(kvm, 0x402);
>>>>>> +	ioport__unregister(kvm, 0x03D5);
>>>>>> +	ioport__unregister(kvm, 0x03D4);
>>>>>> +	ioport__unregister(kvm, 0x0378);
>>>>>> +	ioport__unregister(kvm, 0x0278);
>>>>>> +	ioport__unregister(kvm, 0x00F0);
>>>>>> +	ioport__unregister(kvm, 0x00ED);
>>>>>> +	ioport__unregister(kvm, IOPORT_DBG);
>>>>>> +	ioport__unregister(kvm, 0x00C0);
>>>>>> +	ioport__unregister(kvm, 0x00A0);
>>>>>> +	ioport__unregister(kvm, 0x0092);
>>>>>> +	ioport__unregister(kvm, 0x0040);
>>>>>> +	ioport__unregister(kvm, 0x0020);
>>>>>> +	ioport__unregister(kvm, 0x0000);
>>>>>> +
>>>>>> +	return 0;
>>>>>> +}
>>>>>> +dev_base_exit(ioport__remove_arch);      

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

* Re: [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation
  2021-02-17 17:43     ` Andre Przywara
@ 2021-02-22 15:50       ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-22 15:50 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/17/21 5:43 PM, Andre Przywara wrote:
> On Thu, 11 Feb 2021 16:10:16 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> Hi,
>
>> On 12/10/20 2:28 PM, Andre Przywara wrote:
>>> In their core functionality MMIO and I/O port traps are not really
>>> different, yet we still have two totally separate code paths for
>>> handling them. Devices need to decide on one conduit or need to provide
>>> different handler functions for each of them.
>>>
>>> Extend the existing MMIO emulation to also cover ioport handlers.
>>> This just adds another RB tree root for holding the I/O port handlers,
>>> but otherwise uses the same tree population and lookup code.  
>> Maybe I'm missing something, but why two trees? Is it valid to have an overlap
>> between IO port and MMIO emulation? Or was it done to make the removal of ioport
>> emulation easier?
> So I thought about it as well, but figured it's easier this way:
> - x86 allows overlap, PIO is a totally separate address space from
>   memory/MMIO. Early x86 CPUs had pins to indicate a PIO bus cycle, but
>   using the same address and data pins otherwise. In practise there
>   might be no overlap when it comes to *MMIO* traps vs PIO on x86
>   (there is DRAM only at the lowest 64K of the IBM PC memory map),
>   but not sure we should rely on this.
> - For non-x86 this would indeed be non-overlapping, but this would need
>   to be translated at init time then? And then we can't move those
>   anymore, I guess? So I found it cleaner to keep this separate, and do
>   the translation at trap time.
> - As a consequence we would need to have a bit indicating the address
>   space. I haven't actually tried this, but my understanding is that
>   this would spoil the whole rb_tree functions, since they rely on a
>   linear addressing scheme, and adding another bit there would be at
>   least cumbersome?
>
> At the end I decided to go for separate trees, as also this was less
> change.
>
> I agree that it would be nice to have one tree, from a design point of
> view, but I am afraid that would require more changes.
> If need be, I think we can always unify them later on, on top of this
> series?

Definitely later, I forgot that x86 uses special instructions to access IO ports,
which means that port addresses can overlap with memory addresses. Let's keep 2
trees for now and we can decide later if we should unify them for the other
architectures.

>
>> If it's not valid to have that overlap, then I think having one tree for both
>> would better. Struct mmio_mapping would have to be augmented with a flags field
>> that holds the same flags given to kvm__register_iotrap to differentiate between
>> the two slightly different emulations. Saving the IOTRAP_COALESCE flag would also
>> make it trivial to call KVM_UNREGISTER_COALESCED_MMIO in kvm__deregister_iotrap,
>> which we currently don't do.
>>
>>> "ioport" or "mmio" just become a flag in the registration function.
>>> Provide wrappers to not break existing users, and allow an easy
>>> transition for the existing ioport handlers.
>>>
>>> This also means that ioport handlers now can use the same emulation
>>> callback prototype as MMIO handlers, which means we have to migrate them
>>> over. To allow a smooth transition, we hook up the new I/O emulate
>>> function to the end of the existing ioport emulation code.  
>> I'm sorry, but I don't understand that last sentence. Do you mean that the ioport
>> emulation code has been modified to use kvm__emulate_pio() as a fallback for when
>> the port is not found in the ioport_tree?
> I meant that for the transition period we have all of traditional MMIO,
> traditional PIO, *and* just transformed PIO.
>
> That means there are still PIO devices registered through ioport.c's
> ioport__register(), *and* PIO devices registered through mmio.c's
> kvm__register_pio(). Which means they end up in two separate PIO trees.
> And only the traditional kvm__emulate_io() from ioport.c is called upon
> a trap, so it needs to check both trees, which it does by calling into
> kvm__emulate_pio(), shall a search in the local tree fail.

Thank you for the explanation, now it makes sense.

>
> Or did you mean something else?
>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  include/kvm/kvm.h | 42 +++++++++++++++++++++++++++++----
>>>  ioport.c          |  4 ++--
>>>  mmio.c            | 59 +++++++++++++++++++++++++++++++++++++++--------
>>>  3 files changed, 89 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h
>>> index ee99c28e..14f9d58b 100644
>>> --- a/include/kvm/kvm.h
>>> +++ b/include/kvm/kvm.h
>>> @@ -27,10 +27,16 @@
>>>  #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
>>>  #endif
>>>  
>>> +#define IOTRAP_BUS_MASK		0xf  
>> It's not immediately obvious what this mask does. It turns out it's used to mask
>> the enum flags defined in the header devices.h, header which is not included in
>> this file.
>>
>> The flag names we pass to kvm__register_iotrap() are slightly inconsistent
>> (DEVICE_BUS_PCI, DEVICE_BUS_MMIO and IOTRAP_COALESCE), where DEVICE_BUS_{PCI,
>> MMIO} come from devices.h as an enum. I was wondering if I'm missing something and
>> there is a particular reason why we don't define our own flags for that here
>> (something like IOTRAP_PIO and IOTRAP_MMIO).
> I am not sure why this would be needed?
> We already define and use DEVICE_BUS_x elsewhere, so why not re-use it?

To check if we should coalesce the MMIO regions we check the IOTRAP_COALESCE bit,
but to check if we should use the mmio or io tree we use a mask over the first 4
bits and compare that to DEVICE_BUS_xxx. I find that confusing: the
IOTRAP_BUS_MASK and IOTRAP_COALESCE are defined here, but there is no evidence
where the other flags are coming from, and the header file devices.h isn't even
included.

>
>> If we do decide to keep the flags from devices.h, I think it would be worth it to
>> have a compile time check (with BUILD_BUG_ON) that IOTRAP_BUS_MASK is >=
>> DEVICES_BUS_MAX, which would also be a good indication of where those flags are
>> coming from.
> Well, if that makes you happy, I am not sure we gain another 13 bus
> types anytime soon, though ;-)

I was actually suggesting that more for documenting the code. If we compare
IOTRAP_BUS_MASK with DEVICE_BUS_MAX, then that will give us a hint where we're
expecting the flags to be defined.

But I had another look at the code and it seems that DEVICE_BUS_MMIO = 1 and
DEVICE_BUS_IOPORT = 2, which means that we don't need the mask and we can check
the bits instead (and IOTRAP_COALESCE can be redefined to be 1U << 2). I think
dropping the mask and replacing it with testing individual bits would make the
code easier to follow, what do you think?

>  
>>> +#define IOTRAP_COALESCE		(1U << 4)
>>> +
>>>  #define DEFINE_KVM_EXT(ext)		\
>>>  	.name = #ext,			\
>>>  	.code = ext
>>>  
>>> +struct kvm_cpu;
>>> +typedef void (*mmio_handler_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data,
>>> +				u32 len, u8 is_write, void *ptr);
>>>  typedef void (*fdt_irq_fn)(void *fdt, u8 irq, enum irq_type);
>>>  
>>>  enum {
>>> @@ -113,6 +119,8 @@ void kvm__irq_line(struct kvm *kvm, int irq, int level);
>>>  void kvm__irq_trigger(struct kvm *kvm, int irq);
>>>  bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, int size, u32 count);
>>>  bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write);
>>> +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
>>> +		      int direction, int size, u32 count);
>>>  int kvm__destroy_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
>>>  int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr,
>>>  		      enum kvm_mem_type type);
>>> @@ -136,10 +144,36 @@ static inline int kvm__reserve_mem(struct kvm *kvm, u64 guest_phys, u64 size)
>>>  				 KVM_MEM_TYPE_RESERVED);
>>>  }
>>>  
>>> -int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
>>> -				    void (*mmio_fn)(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
>>> -				    void *ptr);
>>> -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
>>> +int __must_check kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64 len,
>>> +				      mmio_handler_fn mmio_fn, void *ptr,
>>> +				      unsigned int flags);
>>> +
>>> +static inline
>>> +int __must_check kvm__register_mmio(struct kvm *kvm, u64 phys_addr,
>>> +				    u64 phys_addr_len, bool coalesce,
>>> +				    mmio_handler_fn mmio_fn, void *ptr)
>>> +{
>>> +	return kvm__register_iotrap(kvm, phys_addr, phys_addr_len, mmio_fn, ptr,
>>> +			DEVICE_BUS_MMIO | (coalesce ? IOTRAP_COALESCE : 0));
>>> +}
>>> +static inline
>>> +int __must_check kvm__register_pio(struct kvm *kvm, u16 port, u16 len,
>>> +				   mmio_handler_fn mmio_fn, void *ptr)
>>> +{
>>> +	return kvm__register_iotrap(kvm, port, len, mmio_fn, ptr,
>>> +				    DEVICE_BUS_IOPORT);
>>> +}
>>> +
>>> +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr, unsigned int flags);
>>> +static inline bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
>>> +{
>>> +	return kvm__deregister_iotrap(kvm, phys_addr, DEVICE_BUS_MMIO);
>>> +}
>>> +static inline bool kvm__deregister_pio(struct kvm *kvm, u16 port)
>>> +{
>>> +	return kvm__deregister_iotrap(kvm, port, DEVICE_BUS_IOPORT);
>>> +}
>>> +
>>>  void kvm__reboot(struct kvm *kvm);
>>>  void kvm__pause(struct kvm *kvm);
>>>  void kvm__continue(struct kvm *kvm);
>>> diff --git a/ioport.c b/ioport.c
>>> index b98836d3..204d8103 100644
>>> --- a/ioport.c
>>> +++ b/ioport.c
>>> @@ -147,7 +147,8 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction,
>>>  
>>>  	entry = ioport_get(&ioport_tree, port);
>>>  	if (!entry)
>>> -		goto out;
>>> +		return kvm__emulate_pio(vcpu, port, data, direction,
>>> +					size, count);  
>> I have to admit this gave me pause because this patch doesn't add any users for
>> kvm__register_pio() (although with this change the behaviour of kvm__emulate_io()
>> remains exactly the same). Do you think this change would fit better in patch #7,
>> where the first user for kvm__register_pio() is added, or do you prefer it here?
> I think it logically belongs here, as we introduce the
> kvm__emulate_pio() function here as well. Otherwise this function would
> have no caller. As it is now, it's just a "coincidence" that no one
> actually called kvm__register_pio() so far. This also makes the other
> patches movable and replaceable: this patch prepares the stage, the
> follow-up patches just fill it.

Sure, makes sense.

>
>>>  
>>>  	ops	= entry->ops;
>>>  
>>> @@ -162,7 +163,6 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16
>>> port, void *data, int direction, 
>>>  	ioport_put(&ioport_tree, entry);
>>>  
>>> -out:
>>>  	if (ret)
>>>  		return true;
>>>  
>>> diff --git a/mmio.c b/mmio.c
>>> index cd141cd3..4cce1901 100644
>>> --- a/mmio.c
>>> +++ b/mmio.c
>>> @@ -19,13 +19,14 @@ static DEFINE_MUTEX(mmio_lock);
>>>  
>>>  struct mmio_mapping {
>>>  	struct rb_int_node	node;
>>> -	void			(*mmio_fn)(struct kvm_cpu
>>> *vcpu, u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
>>> +	mmio_handler_fn		mmio_fn;
>>>  	void			*ptr;
>>>  	u32			refcount;
>>>  	bool			remove;
>>>  };
>>>  
>>>  static struct rb_root mmio_tree = RB_ROOT;
>>> +static struct rb_root pio_tree = RB_ROOT;
>>>  
>>>  static struct mmio_mapping *mmio_search(struct rb_root *root, u64
>>> addr, u64 len) {
>>> @@ -103,9 +104,9 @@ static void mmio_put(struct kvm *kvm, struct
>>> rb_root *root, struct mmio_mapping mutex_unlock(&mmio_lock);
>>>  }
>>>  
>>> -int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64
>>> phys_addr_len, bool coalesce,
>>> -		       void (*mmio_fn)(struct kvm_cpu *vcpu, u64
>>> addr, u8 *data, u32 len, u8 is_write, void *ptr),
>>> -			void *ptr)
>>> +int kvm__register_iotrap(struct kvm *kvm, u64 phys_addr, u64
>>> phys_addr_len,
>>> +			 mmio_handler_fn mmio_fn, void *ptr,
>>> +			 unsigned int flags)
>>>  {
>>>  	struct mmio_mapping *mmio;
>>>  	struct kvm_coalesced_mmio_zone zone;
>>> @@ -127,7 +128,7 @@ int kvm__register_mmio(struct kvm *kvm, u64
>>> phys_addr, u64 phys_addr_len, bool c .remove		= false,
>>>  	};
>>>  
>>> -	if (coalesce) {
>>> +	if (flags & IOTRAP_COALESCE) {  
>> There is no such flag being used in ioport.c, is it valid to have the
>> flags DEVICE_BUS_IOPORT and IOTRAP_COALESCE set at the same time?
> Well, yes and no: Yes, as this maps to MMIO on non-x86, so
> theoretically could use the flag. No, as no one registering a trap
> handler through kvm__register_pio() would ever have the chance to set
> this flag.
> I can check for the registration being for the MMIO bus before entering
> the "if" branch, if that is what you mean?

Yes, that's what I mean, please return an error if a device tries to register an
I/O port and sets the COALESCE flag, since that's forbidden for architectures with
true I/O ports (like x86). I realize it might look peculiar since we don't have
any devices that do that, but I think it can be useful for catching errors when
writing new devices.

Thanks,

Alex

>
>>>  		zone = (struct kvm_coalesced_mmio_zone) {
>>>  			.addr	= phys_addr,
>>>  			.size	= phys_addr_len,
>>> @@ -139,18 +140,27 @@ int kvm__register_mmio(struct kvm *kvm, u64
>>> phys_addr, u64 phys_addr_len, bool c }
>>>  	}
>>>  	mutex_lock(&mmio_lock);
>>> -	ret = mmio_insert(&mmio_tree, mmio);
>>> +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
>>> +		ret = mmio_insert(&pio_tree, mmio);
>>> +	else
>>> +		ret = mmio_insert(&mmio_tree, mmio);
>>>  	mutex_unlock(&mmio_lock);
>>>  
>>>  	return ret;
>>>  }
>>>  
>>> -bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
>>> +bool kvm__deregister_iotrap(struct kvm *kvm, u64 phys_addr,
>>> unsigned int flags) {
>>>  	struct mmio_mapping *mmio;
>>> +	struct rb_root *tree;
>>> +
>>> +	if ((flags & IOTRAP_BUS_MASK) == DEVICE_BUS_IOPORT)
>>> +		tree = &pio_tree;
>>> +	else
>>> +		tree = &mmio_tree;
>>>  
>>>  	mutex_lock(&mmio_lock);
>>> -	mmio = mmio_search_single(&mmio_tree, phys_addr);
>>> +	mmio = mmio_search_single(tree, phys_addr);
>>>  	if (mmio == NULL) {
>>>  		mutex_unlock(&mmio_lock);
>>>  		return false;
>>> @@ -167,7 +177,7 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64
>>> phys_addr)
>>>  	 * called mmio_put(). This will trigger use-after-free
>>> errors on VCPU0. */
>>>  	if (mmio->refcount == 0)
>>> -		mmio_deregister(kvm, &mmio_tree, mmio);
>>> +		mmio_deregister(kvm, tree, mmio);
>>>  	else
>>>  		mmio->remove = true;
>>>  	mutex_unlock(&mmio_lock);
>>> @@ -175,7 +185,8 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64
>>> phys_addr) return true;
>>>  }
>>>  
>>> -bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8
>>> *data, u32 len, u8 is_write) +bool kvm__emulate_mmio(struct kvm_cpu
>>> *vcpu, u64 phys_addr, u8 *data,
>>> +		       u32 len, u8 is_write)  
>> I don't think style changes should be part of this patch, the patch
>> is large enough as it is.
> I see, I just figured it's not worth a separate patch either.
>
> Cheers,
> Andre
>
>>>  {
>>>  	struct mmio_mapping *mmio;
>>>  
>>> @@ -194,3 +205,31 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu,
>>> u64 phys_addr, u8 *data, u32 len, u out:
>>>  	return true;
>>>  }
>>> +
>>> +bool kvm__emulate_pio(struct kvm_cpu *vcpu, u16 port, void *data,
>>> +		     int direction, int size, u32 count)
>>> +{
>>> +	struct mmio_mapping *mmio;
>>> +	bool is_write = direction == KVM_EXIT_IO_OUT;
>>> +
>>> +	mmio = mmio_get(&pio_tree, port, size);
>>> +	if (!mmio) {
>>> +		if (vcpu->kvm->cfg.ioport_debug) {
>>> +			fprintf(stderr, "IO error: %s port=%x,
>>> size=%d, count=%u\n",
>>> +				to_direction(direction), port,
>>> size, count); +
>>> +			return false;
>>> +		}
>>> +		return true;
>>> +	}
>>> +
>>> +	while (count--) {
>>> +		mmio->mmio_fn(vcpu, port, data, size, is_write,
>>> mmio->ptr); +
>>> +		data += size;
>>> +	}
>>> +
>>> +	mmio_put(vcpu->kvm, &pio_tree, mmio);
>>> +
>>> +	return true;
>>> +}  

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

* Re: [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler
  2021-02-18 11:48         ` Andre Przywara
@ 2021-02-22 16:03           ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-22 16:03 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/18/21 11:48 AM, Andre Przywara wrote:
> On Thu, 18 Feb 2021 11:17:58 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
>> Hi Andre,
>>
>> On 2/18/21 10:34 AM, Andre Przywara wrote:
>>> On Thu, 11 Feb 2021 17:23:13 +0000
>>> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>>>  
>>>> Hi Andre,
>>>>
>>>> On 12/10/20 2:28 PM, Andre Przywara wrote:  
>>>>> With the planned retirement of the special ioport emulation code, we
>>>>> need to provide an emulation function compatible with the MMIO
>>>>> prototype.
>>>>>
>>>>> Adjust the trap handler to use that new function, and provide shims to
>>>>> implement the old ioport interface, for now.
>>>>>
>>>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>>>> ---
>>>>>  hw/i8042.c | 68 +++++++++++++++++++++++++++---------------------------
>>>>>  1 file changed, 34 insertions(+), 34 deletions(-)
>>>>>
>>>>> diff --git a/hw/i8042.c b/hw/i8042.c
>>>>> index 36ee183f..eb1f9d28 100644
>>>>> --- a/hw/i8042.c
>>>>> +++ b/hw/i8042.c
>>>>> @@ -292,52 +292,52 @@ static void kbd_reset(void)
>>>>>  	};
>>>>>  }
>>>>>  
>>>>> -/*
>>>>> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
>>>>> - */
>>>>> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>>>> +static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>>>>> +		   u8 is_write, void *ptr)
>>>>>  {
>>>>> -	switch (port) {
>>>>> -	case I8042_COMMAND_REG: {
>>>>> -		u8 value = kbd_read_status();
>>>>> -		ioport__write8(data, value);
>>>>> +	u8 value;
>>>>> +
>>>>> +	if (is_write)
>>>>> +		value = ioport__read8(data);
>>>>> +
>>>>> +	switch (addr) {
>>>>> +	case I8042_COMMAND_REG:
>>>>> +		if (is_write)
>>>>> +			kbd_write_command(vcpu->kvm, value);
>>>>> +		else
>>>>> +			value = kbd_read_status();
>>>>>  		break;
>>>>> -	}
>>>>> -	case I8042_DATA_REG: {
>>>>> -		u8 value = kbd_read_data();
>>>>> -		ioport__write8(data, value);
>>>>> +	case I8042_DATA_REG:
>>>>> +		if (is_write)
>>>>> +			kbd_write_data(value);
>>>>> +		else
>>>>> +			value = kbd_read_data();
>>>>>  		break;
>>>>> -	}
>>>>> -	case I8042_PORT_B_REG: {
>>>>> -		ioport__write8(data, 0x20);
>>>>> +	case I8042_PORT_B_REG:
>>>>> +		if (!is_write)
>>>>> +			value = 0x20;
>>>>>  		break;
>>>>> -	}
>>>>>  	default:
>>>>> -		return false;
>>>>> +		return;    
>>>> Any particular reason for removing the false return value? I don't see it
>>>> mentioned in the commit message. Otherwise this is identical to the two functions
>>>> it replaces.  
>>> Because the MMIO handler prototype is void, in contrast to the PIO one.
>>> Since on returning "false" we only seem to panic kvmtool, this is of
>>> quite limited use, I'd say.  
>> Actually, in ioport.c::kvm__emulate_io(), if kvm->cfg.ioport_debug is true, it
>> will print an error and then panic in kvm_cpu__start(); otherwise the error is
>> silently ignored. serial.c is another device where an unknown register returns
>> false. In rtc.c, the unknown register is ignored. cfi_flash.c prints debugging
>> information. So I guess kvmtool implements all possible methods of handling an
>> unknown register *at the same time*, so it's up to you how you want to handle it.
> Well, the MMIO prototype we are going to use is void anyway, so it's
> just one patch earlier that we get this new behaviour.
> For handling MMIO errors:
> - Hardware MMIO doesn't have a back channel: if the MMIO write triggers
>   some error condition, the device would need to deal with it (setting
>   internal error state, ignore, etc.). On some systems the device could
>   throw some kind of bus error or SError, but this is a rather drastic
>   measure, and is certainly not exercised by those ancient devices.
> - Any kind of error reporting which can be triggered by a guest is
>   frowned upon: it could spam the console or some log file, and so
>   impact host operation. At the end an administrator can't do much about
>   it, anyway.
> - Which leaves the only use to some kvmtool developer debugging some
>   device emulation or investigating weird guest behaviour. And in this
>   case we can more easily have a debug message *inside* the device
>   emulation code, can't we?

That's what I had in mind, debugging messages in the device emulation. If the
guest can access an unknown register offset this can mean one of two things in my
opinion: the emulated device registered a memory region bigger that necessary or
the emulated device is not handling all device registers. But that's a subject for
another series.

Thanks,

Alex

>
> And since the MMIO handler prototype is void, we have no choice anyway,
> at least not without another huge (and pointless) series to change
> those user as well ;-)
>
> Cheers,
> Andre
>
>>>>>  	}
>>>>>  
>>>>> +	if (!is_write)
>>>>> +		ioport__write8(data, value);
>>>>> +}
>>>>> +
>>>>> +/*
>>>>> + * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
>>>>> + */
>>>>> +static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>>>> +{
>>>>> +	kbd_io(vcpu, port, data, size, false, NULL);    
>>>> is_write is an u8, not a bool.  
>>> Right, will fix this.
>>>  
>>>> I never could wrap my head around the ioport convention of "in" (read) and "out"
>>>> (write). To be honest, changing is_write changed to an enum so it's crystal clear
>>>> what is happening would help with that a lot, but I guess that's a separate patch.  
>>> "in" and "out" are the x86 assembly mnemonics, but it's indeed
>>> confusing, because the device side has a different view (CPU "in" means
>>> pushing data "out" of the device). I usually look at the code to see
>>> what it's actually meant to do.
>>> So yeah, I feel like a lot of those device emulations could use
>>> some update. but that's indeed something for another day.  
>> Agreed.
>>
>> Thanks,
>>
>> Alex
>>
>>> Cheers,
>>> Andre
>>>  
>>>>> +
>>>>>  	return true;
>>>>>  }
>>>>>  
>>>>>  static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>>>>  {
>>>>> -	switch (port) {
>>>>> -	case I8042_COMMAND_REG: {
>>>>> -		u8 value = ioport__read8(data);
>>>>> -		kbd_write_command(vcpu->kvm, value);
>>>>> -		break;
>>>>> -	}
>>>>> -	case I8042_DATA_REG: {
>>>>> -		u8 value = ioport__read8(data);
>>>>> -		kbd_write_data(value);
>>>>> -		break;
>>>>> -	}
>>>>> -	case I8042_PORT_B_REG: {
>>>>> -		break;
>>>>> -	}
>>>>> -	default:
>>>>> -		return false;
>>>>> -	}
>>>>> +	kbd_io(vcpu, port, data, size, true, NULL);
>>>>>  
>>>>>  	return true;
>>>>>  }    

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

* Re: [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers
  2021-02-18 12:09     ` Andre Przywara
@ 2021-02-22 16:19       ` Alexandru Elisei
  0 siblings, 0 replies; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-22 16:19 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/18/21 12:09 PM, Andre Przywara wrote:
> On Fri, 12 Feb 2021 10:41:20 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
> Hi,
>
>> On 12/10/20 2:28 PM, Andre Przywara wrote:
>>> Now that the PC keyboard has a trap handler adhering to the MMIO fault
>>> handler prototype, let's switch over to the joint registration routine.
>>>
>>> This allows us to get rid of the ioport shim routines.
>>>
>>> Make the kbd_init() function static on the way.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  hw/i8042.c          | 30 ++++--------------------------
>>>  include/kvm/i8042.h |  1 -
>>>  2 files changed, 4 insertions(+), 27 deletions(-)
>>>
>>> diff --git a/hw/i8042.c b/hw/i8042.c
>>> index eb1f9d28..91d79dc4 100644
>>> --- a/hw/i8042.c
>>> +++ b/hw/i8042.c
>>> @@ -325,40 +325,18 @@ static void kbd_io(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>>>  		ioport__write8(data, value);
>>>  }
>>>  
>>> -/*
>>> - * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
>>> - */
>>> -static bool kbd_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>> -{
>>> -	kbd_io(vcpu, port, data, size, false, NULL);
>>> -
>>> -	return true;
>>> -}
>>> -
>>> -static bool kbd_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>> -{
>>> -	kbd_io(vcpu, port, data, size, true, NULL);
>>> -
>>> -	return true;
>>> -}
>>> -
>>> -static struct ioport_operations kbd_ops = {
>>> -	.io_in		= kbd_in,
>>> -	.io_out		= kbd_out,
>>> -};
>>> -
>>> -int kbd__init(struct kvm *kvm)
>>> +static int kbd__init(struct kvm *kvm)
>>>  {
>>>  	int r;
>>>  
>>>  	kbd_reset();
>>>  	state.kvm = kvm;
>>> -	r = ioport__register(kvm, I8042_DATA_REG, &kbd_ops, 2, NULL);
>>> +	r = kvm__register_pio(kvm, I8042_DATA_REG, 2, kbd_io, NULL);  
>> I guess you are registering two addresses here to cover I8042_PORT_B_REG, right?
>> Might be worth a comment.
> I am registering two ports because the original code did, and I didn't
> dare to touch this. I guess we put this on the wishlist for the device
> emulation fixup series? ;-)
>
> Maybe the intention was to just *reserve* those ports?

Considering that I8042_DATA_REG = 0x60 and I8042_PORT_B_REG = 0x61, and the
emulation handlers handle both of them, I'm pretty sure the intention was to
reserve memory to cover both ports.

>
>>>  	if (r < 0)
>>>  		return r;
>>> -	r = ioport__register(kvm, I8042_COMMAND_REG, &kbd_ops, 2, NULL);
>>> +	r = kvm__register_pio(kvm, I8042_COMMAND_REG, 2, kbd_io, NULL);  
>> Shouldn't length be 1? The emulation should work only for address 0x64
>> (command/status register), right? Or am I missing something?
> I don't think you are, same as above. Maybe some weird guest is using
> half-word accesses (outw)?

I think you're right, let's not mess with the device emulation right now, after
all that's not the purpose of the series. And I'm fairly confident you know more
about the device and the x86 architecture than me, so I'll trust your judgement on
this.

Thanks,

Alex

>
> Cheers,
> Andre
>
>
>> Thanks,
>>
>> Alex
>>
>>>  	if (r < 0) {
>>> -		ioport__unregister(kvm, I8042_DATA_REG);
>>> +		kvm__deregister_pio(kvm, I8042_DATA_REG);
>>>  		return r;
>>>  	}
>>>  
>>> diff --git a/include/kvm/i8042.h b/include/kvm/i8042.h
>>> index 3b4ab688..cd4ae6bb 100644
>>> --- a/include/kvm/i8042.h
>>> +++ b/include/kvm/i8042.h
>>> @@ -7,6 +7,5 @@ struct kvm;
>>>  
>>>  void mouse_queue(u8 c);
>>>  void kbd_queue(u8 c);
>>> -int kbd__init(struct kvm *kvm);
>>>  
>>>  #endif  

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

* Re: [PATCH kvmtool 13/21] hw/serial: Refactor trap handler
  2021-02-18 14:41     ` Andre Przywara
@ 2021-02-22 17:40       ` Alexandru Elisei
  2021-02-24 14:54         ` Andre Przywara
  0 siblings, 1 reply; 72+ messages in thread
From: Alexandru Elisei @ 2021-02-22 17:40 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

Hi Andre,

On 2/18/21 2:41 PM, Andre Przywara wrote:
> On Tue, 16 Feb 2021 14:22:05 +0000
> Alexandru Elisei <alexandru.elisei@arm.com> wrote:
>
>> Hi Andre,
>>
>> Patch looks good, nitpicks below.
>>
>> On 12/10/20 2:29 PM, Andre Przywara wrote:
>>> With the planned retirement of the special ioport emulation code, we
>>> need to provide an emulation function compatible with the MMIO prototype.
>>>
>>> Adjust the trap handler to use that new function, and provide shims to
>>> implement the old ioport interface, for now.
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>  hw/serial.c | 97 +++++++++++++++++++++++++++++++++++------------------
>>>  1 file changed, 65 insertions(+), 32 deletions(-)
>>>
>>> diff --git a/hw/serial.c b/hw/serial.c
>>> index b0465d99..2907089c 100644
>>> --- a/hw/serial.c
>>> +++ b/hw/serial.c
>>> @@ -242,36 +242,31 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
>>>  	sysrq_pending = sysrq;
>>>  }
>>>  
>>> -static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
>>> -			   void *data, int size)
>>> +static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
>>> +			   u16 offset, u8 data)
>>>  {
>>> -	struct serial8250_device *dev = ioport->priv;
>>> -	u16 offset;
>>>  	bool ret = true;
>>> -	char *addr = data;
>>>  
>>>  	mutex_lock(&dev->mutex);
>>>  
>>> -	offset = port - dev->iobase;
>>> -
>>>  	switch (offset) {
>>>  	case UART_TX:
>>>  		if (dev->lcr & UART_LCR_DLAB) {
>>> -			dev->dll = ioport__read8(data);
>>> +			dev->dll = data;
>>>  			break;
>>>  		}
>>>  
>>>  		/* Loopback mode */
>>>  		if (dev->mcr & UART_MCR_LOOP) {
>>>  			if (dev->rxcnt < FIFO_LEN) {
>>> -				dev->rxbuf[dev->rxcnt++] = *addr;
>>> +				dev->rxbuf[dev->rxcnt++] = data;
>>>  				dev->lsr |= UART_LSR_DR;
>>>  			}
>>>  			break;
>>>  		}
>>>  
>>>  		if (dev->txcnt < FIFO_LEN) {
>>> -			dev->txbuf[dev->txcnt++] = *addr;
>>> +			dev->txbuf[dev->txcnt++] = data;
>>>  			dev->lsr &= ~UART_LSR_TEMT;
>>>  			if (dev->txcnt == FIFO_LEN / 2)
>>>  				dev->lsr &= ~UART_LSR_THRE;
>>> @@ -283,18 +278,18 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
>>>  		break;
>>>  	case UART_IER:
>>>  		if (!(dev->lcr & UART_LCR_DLAB))
>>> -			dev->ier = ioport__read8(data) & 0x0f;
>>> +			dev->ier = data & 0x0f;
>>>  		else
>>> -			dev->dlm = ioport__read8(data);
>>> +			dev->dlm = data;
>>>  		break;
>>>  	case UART_FCR:
>>> -		dev->fcr = ioport__read8(data);
>>> +		dev->fcr = data;
>>>  		break;
>>>  	case UART_LCR:
>>> -		dev->lcr = ioport__read8(data);
>>> +		dev->lcr = data;
>>>  		break;
>>>  	case UART_MCR:
>>> -		dev->mcr = ioport__read8(data);
>>> +		dev->mcr = data;
>>>  		break;
>>>  	case UART_LSR:
>>>  		/* Factory test */
>>> @@ -303,7 +298,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
>>>  		/* Not used */
>>>  		break;
>>>  	case UART_SCR:
>>> -		dev->scr = ioport__read8(data);
>>> +		dev->scr = data;
>>>  		break;
>>>  	default:
>>>  		ret = false;
>>> @@ -336,46 +331,43 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
>>>  	}
>>>  }
>>>  
>>> -static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
>>> +static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
>>> +			  u16 offset, u8 *data)
>>>  {
>>> -	struct serial8250_device *dev = ioport->priv;
>>> -	u16 offset;
>>>  	bool ret = true;
>>>  
>>>  	mutex_lock(&dev->mutex);
>>>  
>>> -	offset = port - dev->iobase;
>>> -
>>>  	switch (offset) {
>>>  	case UART_RX:
>>>  		if (dev->lcr & UART_LCR_DLAB)
>>> -			ioport__write8(data, dev->dll);
>>> +			*data = dev->dll;
>>>  		else
>>>  			serial8250_rx(dev, data);
>>>  		break;
>>>  	case UART_IER:
>>>  		if (dev->lcr & UART_LCR_DLAB)
>>> -			ioport__write8(data, dev->dlm);
>>> +			*data = dev->dlm;
>>>  		else
>>> -			ioport__write8(data, dev->ier);
>>> +			*data = dev->ier;
>>>  		break;
>>>  	case UART_IIR:
>>> -		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
>>> +		*data = dev->iir | UART_IIR_TYPE_BITS;
>>>  		break;
>>>  	case UART_LCR:
>>> -		ioport__write8(data, dev->lcr);
>>> +		*data = dev->lcr;
>>>  		break;
>>>  	case UART_MCR:
>>> -		ioport__write8(data, dev->mcr);
>>> +		*data = dev->mcr;
>>>  		break;
>>>  	case UART_LSR:
>>> -		ioport__write8(data, dev->lsr);
>>> +		*data = dev->lsr;
>>>  		break;
>>>  	case UART_MSR:
>>> -		ioport__write8(data, dev->msr);
>>> +		*data = dev->msr;
>>>  		break;
>>>  	case UART_SCR:
>>> -		ioport__write8(data, dev->scr);
>>> +		*data = dev->scr;
>>>  		break;
>>>  	default:
>>>  		ret = false;
>>> @@ -389,6 +381,47 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
>>>  	return ret;
>>>  }
>>>  
>>> +static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
>>> +			    u8 is_write, void *ptr)
>>> +{
>>> +	struct serial8250_device *dev = ptr;
>>> +	u8 value = 0;
>>> +
>>> +	if (is_write) {
>>> +		 value = *data;  
>> Extra space before value.
>>
>>> +
>>> +		serial8250_out(dev, vcpu, addr - dev->iobase, value);
>>> +	} else {
>>> +		if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
>>> +			*data = value;
>>> +	}
>>> +}
>>> +
>>> +static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
>>> +				  u16 port, void *data, int size)
>>> +{
>>> +	struct serial8250_device *dev = ioport->priv;
>>> +	u8 value = ioport__read8(data);
>>> +
>>> +	serial8250_mmio(vcpu, port, &value, 1, true, dev);
>>> +
>>> +	return true;
>>> +}
>>> +
>>> +static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
>>> +				 u16 port, void *data, int size)
>>> +{
>>> +	struct serial8250_device *dev = ioport->priv;
>>> +	u8 value = 0;
>>> +
>>> +
>>> +	serial8250_mmio(vcpu, port, &value, 1, false, dev);
>>> +
>>> +	ioport__write8(data, value);  
>> This is correct, but confusing. You pass the address of a local variable as *data
>> to serial8250_mmio, serial8250_mmio conditionally updates the value at data (which
>> is &value from here), and then here we update the *data unconditionally. Why not
>> pass data directly to serial8250_mmio and skip the local variable? Am I missing
>> something?
> The idea is to keep the abstraction of ioport__write<x>. I agree this
> is somewhat pointless for a single byte write, since the purpose of
> those wrappers is to deal with endianness, but it seems nice to use
> that anyway, anywhere, in case we need to add something to the wrappers
> at some point.

What I was thinking was something like this:

@@ -385,25 +386,19 @@ static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr,
u8 *data, u32 len,
                            u8 is_write, void *ptr)
 {
        struct serial8250_device *dev = ptr;
-       u8 value = 0;
 
-       if (is_write) {
-                value = *data;
-
-               serial8250_out(dev, vcpu, addr - dev->iobase, value);
-       } else {
-               if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
-                       *data = value;
-       }
+       if (is_write)
+               serial8250_out(dev, vcpu, addr - dev->iobase, data);
+       else
+               serial8250_in(dev, vcpu, addr - dev->iobase, data);
 }
 
 static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
                                  u16 port, void *data, int size)
 {
        struct serial8250_device *dev = ioport->priv;
-       u8 value = ioport__read8(data);
 
-       serial8250_mmio(vcpu, port, &value, 1, true, dev);
+       serial8250_mmio(vcpu, port, data, 1, true, dev);
 
        return true;
 }
@@ -412,12 +407,8 @@ static bool serial8250_ioport_in(struct ioport *ioport,
struct kvm_cpu *vcpu,
                                 u16 port, void *data, int size)
 {
        struct serial8250_device *dev = ioport->priv;
-       u8 value = 0;
-
-
-       serial8250_mmio(vcpu, port, &value, 1, false, dev);
 
-       ioport__write8(data, value);
+       serial8250_mmio(vcpu, port, data, 1, false, dev);
 
        return true;
 }

And the ioport_{read,write}8 function will used inside the serial8250_{out,in}
functions, like they were before this patch, which should also make the diff
smaller. Or is there something that I'm missing which makes this unfeasible?

Thanks,

Alex

> ioport__write8() is a static inline in a header file, so it shouldn't
> really hurt, the compiler is able to see through it. The generated code
> is almost the same, at least.
>
> Let me know what you think!
>
> Cheers,
> Andre
>
>>> +
>>> +	return true;
>>> +}
>>> +
>>>  #ifdef CONFIG_HAS_LIBFDT
>>>  
>>>  char *fdt_stdout_path = NULL;
>>> @@ -427,8 +460,8 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
>>>  #endif
>>>  
>>>  static struct ioport_operations serial8250_ops = {
>>> -	.io_in			= serial8250_in,
>>> -	.io_out			= serial8250_out,
>>> +	.io_in			= serial8250_ioport_in,
>>> +	.io_out			= serial8250_ioport_out,
>>>  };
>>>  
>>>  static int serial8250__device_init(struct kvm *kvm,  

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

* Re: [PATCH kvmtool 13/21] hw/serial: Refactor trap handler
  2021-02-22 17:40       ` Alexandru Elisei
@ 2021-02-24 14:54         ` Andre Przywara
  0 siblings, 0 replies; 72+ messages in thread
From: Andre Przywara @ 2021-02-24 14:54 UTC (permalink / raw)
  To: Alexandru Elisei
  Cc: Will Deacon, Julien Thierry, kvm, kvmarm, linux-arm-kernel, Marc Zyngier

On Mon, 22 Feb 2021 17:40:36 +0000
Alexandru Elisei <alexandru.elisei@arm.com> wrote:

Hi Alex,

> On 2/18/21 2:41 PM, Andre Przywara wrote:
> > On Tue, 16 Feb 2021 14:22:05 +0000
> > Alexandru Elisei <alexandru.elisei@arm.com> wrote:
> >  
> >> Hi Andre,
> >>
> >> Patch looks good, nitpicks below.
> >>
> >> On 12/10/20 2:29 PM, Andre Przywara wrote:  
> >>> With the planned retirement of the special ioport emulation code, we
> >>> need to provide an emulation function compatible with the MMIO prototype.
> >>>
> >>> Adjust the trap handler to use that new function, and provide shims to
> >>> implement the old ioport interface, for now.
> >>>
> >>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> >>> ---
> >>>  hw/serial.c | 97 +++++++++++++++++++++++++++++++++++------------------
> >>>  1 file changed, 65 insertions(+), 32 deletions(-)
> >>>
> >>> diff --git a/hw/serial.c b/hw/serial.c
> >>> index b0465d99..2907089c 100644
> >>> --- a/hw/serial.c
> >>> +++ b/hw/serial.c
> >>> @@ -242,36 +242,31 @@ void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
> >>>  	sysrq_pending = sysrq;
> >>>  }
> >>>  
> >>> -static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
> >>> -			   void *data, int size)
> >>> +static bool serial8250_out(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> >>> +			   u16 offset, u8 data)
> >>>  {
> >>> -	struct serial8250_device *dev = ioport->priv;
> >>> -	u16 offset;
> >>>  	bool ret = true;
> >>> -	char *addr = data;
> >>>  
> >>>  	mutex_lock(&dev->mutex);
> >>>  
> >>> -	offset = port - dev->iobase;
> >>> -
> >>>  	switch (offset) {
> >>>  	case UART_TX:
> >>>  		if (dev->lcr & UART_LCR_DLAB) {
> >>> -			dev->dll = ioport__read8(data);
> >>> +			dev->dll = data;
> >>>  			break;
> >>>  		}
> >>>  
> >>>  		/* Loopback mode */
> >>>  		if (dev->mcr & UART_MCR_LOOP) {
> >>>  			if (dev->rxcnt < FIFO_LEN) {
> >>> -				dev->rxbuf[dev->rxcnt++] = *addr;
> >>> +				dev->rxbuf[dev->rxcnt++] = data;
> >>>  				dev->lsr |= UART_LSR_DR;
> >>>  			}
> >>>  			break;
> >>>  		}
> >>>  
> >>>  		if (dev->txcnt < FIFO_LEN) {
> >>> -			dev->txbuf[dev->txcnt++] = *addr;
> >>> +			dev->txbuf[dev->txcnt++] = data;
> >>>  			dev->lsr &= ~UART_LSR_TEMT;
> >>>  			if (dev->txcnt == FIFO_LEN / 2)
> >>>  				dev->lsr &= ~UART_LSR_THRE;
> >>> @@ -283,18 +278,18 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
> >>>  		break;
> >>>  	case UART_IER:
> >>>  		if (!(dev->lcr & UART_LCR_DLAB))
> >>> -			dev->ier = ioport__read8(data) & 0x0f;
> >>> +			dev->ier = data & 0x0f;
> >>>  		else
> >>> -			dev->dlm = ioport__read8(data);
> >>> +			dev->dlm = data;
> >>>  		break;
> >>>  	case UART_FCR:
> >>> -		dev->fcr = ioport__read8(data);
> >>> +		dev->fcr = data;
> >>>  		break;
> >>>  	case UART_LCR:
> >>> -		dev->lcr = ioport__read8(data);
> >>> +		dev->lcr = data;
> >>>  		break;
> >>>  	case UART_MCR:
> >>> -		dev->mcr = ioport__read8(data);
> >>> +		dev->mcr = data;
> >>>  		break;
> >>>  	case UART_LSR:
> >>>  		/* Factory test */
> >>> @@ -303,7 +298,7 @@ static bool serial8250_out(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port
> >>>  		/* Not used */
> >>>  		break;
> >>>  	case UART_SCR:
> >>> -		dev->scr = ioport__read8(data);
> >>> +		dev->scr = data;
> >>>  		break;
> >>>  	default:
> >>>  		ret = false;
> >>> @@ -336,46 +331,43 @@ static void serial8250_rx(struct serial8250_device *dev, void *data)
> >>>  	}
> >>>  }
> >>>  
> >>> -static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size)
> >>> +static bool serial8250_in(struct serial8250_device *dev, struct kvm_cpu *vcpu,
> >>> +			  u16 offset, u8 *data)
> >>>  {
> >>> -	struct serial8250_device *dev = ioport->priv;
> >>> -	u16 offset;
> >>>  	bool ret = true;
> >>>  
> >>>  	mutex_lock(&dev->mutex);
> >>>  
> >>> -	offset = port - dev->iobase;
> >>> -
> >>>  	switch (offset) {
> >>>  	case UART_RX:
> >>>  		if (dev->lcr & UART_LCR_DLAB)
> >>> -			ioport__write8(data, dev->dll);
> >>> +			*data = dev->dll;
> >>>  		else
> >>>  			serial8250_rx(dev, data);
> >>>  		break;
> >>>  	case UART_IER:
> >>>  		if (dev->lcr & UART_LCR_DLAB)
> >>> -			ioport__write8(data, dev->dlm);
> >>> +			*data = dev->dlm;
> >>>  		else
> >>> -			ioport__write8(data, dev->ier);
> >>> +			*data = dev->ier;
> >>>  		break;
> >>>  	case UART_IIR:
> >>> -		ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
> >>> +		*data = dev->iir | UART_IIR_TYPE_BITS;
> >>>  		break;
> >>>  	case UART_LCR:
> >>> -		ioport__write8(data, dev->lcr);
> >>> +		*data = dev->lcr;
> >>>  		break;
> >>>  	case UART_MCR:
> >>> -		ioport__write8(data, dev->mcr);
> >>> +		*data = dev->mcr;
> >>>  		break;
> >>>  	case UART_LSR:
> >>> -		ioport__write8(data, dev->lsr);
> >>> +		*data = dev->lsr;
> >>>  		break;
> >>>  	case UART_MSR:
> >>> -		ioport__write8(data, dev->msr);
> >>> +		*data = dev->msr;
> >>>  		break;
> >>>  	case UART_SCR:
> >>> -		ioport__write8(data, dev->scr);
> >>> +		*data = dev->scr;
> >>>  		break;
> >>>  	default:
> >>>  		ret = false;
> >>> @@ -389,6 +381,47 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port,
> >>>  	return ret;
> >>>  }
> >>>  
> >>> +static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr, u8 *data, u32 len,
> >>> +			    u8 is_write, void *ptr)
> >>> +{
> >>> +	struct serial8250_device *dev = ptr;
> >>> +	u8 value = 0;
> >>> +
> >>> +	if (is_write) {
> >>> +		 value = *data;    
> >> Extra space before value.
> >>  
> >>> +
> >>> +		serial8250_out(dev, vcpu, addr - dev->iobase, value);
> >>> +	} else {
> >>> +		if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
> >>> +			*data = value;
> >>> +	}
> >>> +}
> >>> +
> >>> +static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
> >>> +				  u16 port, void *data, int size)
> >>> +{
> >>> +	struct serial8250_device *dev = ioport->priv;
> >>> +	u8 value = ioport__read8(data);
> >>> +
> >>> +	serial8250_mmio(vcpu, port, &value, 1, true, dev);
> >>> +
> >>> +	return true;
> >>> +}
> >>> +
> >>> +static bool serial8250_ioport_in(struct ioport *ioport, struct kvm_cpu *vcpu,
> >>> +				 u16 port, void *data, int size)
> >>> +{
> >>> +	struct serial8250_device *dev = ioport->priv;
> >>> +	u8 value = 0;
> >>> +
> >>> +
> >>> +	serial8250_mmio(vcpu, port, &value, 1, false, dev);
> >>> +
> >>> +	ioport__write8(data, value);    
> >> This is correct, but confusing. You pass the address of a local variable as *data
> >> to serial8250_mmio, serial8250_mmio conditionally updates the value at data (which
> >> is &value from here), and then here we update the *data unconditionally. Why not
> >> pass data directly to serial8250_mmio and skip the local variable? Am I missing
> >> something?  
> > The idea is to keep the abstraction of ioport__write<x>. I agree this
> > is somewhat pointless for a single byte write, since the purpose of
> > those wrappers is to deal with endianness, but it seems nice to use
> > that anyway, anywhere, in case we need to add something to the wrappers
> > at some point.  
> 
> What I was thinking was something like this:
> 
> @@ -385,25 +386,19 @@ static void serial8250_mmio(struct kvm_cpu *vcpu, u64 addr,
> u8 *data, u32 len,
>                             u8 is_write, void *ptr)
>  {
>         struct serial8250_device *dev = ptr;
> -       u8 value = 0;
>  
> -       if (is_write) {
> -                value = *data;
> -
> -               serial8250_out(dev, vcpu, addr - dev->iobase, value);
> -       } else {
> -               if (serial8250_in(dev, vcpu, addr - dev->iobase, &value))
> -                       *data = value;
> -       }
> +       if (is_write)
> +               serial8250_out(dev, vcpu, addr - dev->iobase, data);
> +       else
> +               serial8250_in(dev, vcpu, addr - dev->iobase, data);
>  }
>  
>  static bool serial8250_ioport_out(struct ioport *ioport, struct kvm_cpu *vcpu,
>                                   u16 port, void *data, int size)
>  {
>         struct serial8250_device *dev = ioport->priv;
> -       u8 value = ioport__read8(data);
>  
> -       serial8250_mmio(vcpu, port, &value, 1, true, dev);
> +       serial8250_mmio(vcpu, port, data, 1, true, dev);
>  
>         return true;
>  }
> @@ -412,12 +407,8 @@ static bool serial8250_ioport_in(struct ioport *ioport,
> struct kvm_cpu *vcpu,
>                                  u16 port, void *data, int size)
>  {
>         struct serial8250_device *dev = ioport->priv;
> -       u8 value = 0;
> -
> -
> -       serial8250_mmio(vcpu, port, &value, 1, false, dev);
>  
> -       ioport__write8(data, value);
> +       serial8250_mmio(vcpu, port, data, 1, false, dev);
>  
>         return true;
>  }
> 
> And the ioport_{read,write}8 function will used inside the serial8250_{out,in}
> functions, like they were before this patch, which should also make the diff
> smaller. Or is there something that I'm missing which makes this unfeasible?

Now I remember what the problem was:
The comment before the definition of ioport__read16() says the PowerPC
needs to byteswap specifically PCI port I/O, but apparently not MMIO.
So I moved the ioport wrappers out of the actual handlers, and in *this*
patch they are just in the PIO path, so make it fit for both kind of
traps.
Now with dropping the PIO specific path in the next patch we lose this
differentiation. This is not a real problem here, since all accesses
are 8 bit wide only, which doesn't do anything, really.

I think a proper fix for this problem would be to do the byteswapping
*once*, very early (write) or late (read) in the KVM_RUN
exit handling, or in the kvm__emulate_io() function. So that the
whole device emulation always works in native endianness, and can use
pointers at will. But this would obviously be another patch.

So in preparation for this I could drop all usage of
ioport__{read,write}8 from this file, and use pointers all the way.
That wouldn't change anything (since it's byte accesses only anyway),
but would already prepare for this move.

What do you think?

Cheers,
Andre

> > ioport__write8() is a static inline in a header file, so it shouldn't
> > really hurt, the compiler is able to see through it. The generated code
> > is almost the same, at least.
> >
> > Let me know what you think!
> >
> > Cheers,
> > Andre
> >  
> >>> +
> >>> +	return true;
> >>> +}
> >>> +
> >>>  #ifdef CONFIG_HAS_LIBFDT
> >>>  
> >>>  char *fdt_stdout_path = NULL;
> >>> @@ -427,8 +460,8 @@ void serial8250_generate_fdt_node(void *fdt, struct device_header *dev_hdr,
> >>>  #endif
> >>>  
> >>>  static struct ioport_operations serial8250_ops = {
> >>> -	.io_in			= serial8250_in,
> >>> -	.io_out			= serial8250_out,
> >>> +	.io_in			= serial8250_ioport_in,
> >>> +	.io_out			= serial8250_ioport_out,
> >>>  };
> >>>  
> >>>  static int serial8250__device_init(struct kvm *kvm,    


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

end of thread, other threads:[~2021-02-24 15:51 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-10 14:28 [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Andre Przywara
2020-12-10 14:28 ` [PATCH kvmtool 01/21] ioport: Remove ioport__setup_arch() Andre Przywara
2021-02-10 17:44   ` Alexandru Elisei
2021-02-11 17:16     ` Andre Przywara
2021-02-11 17:32       ` Alexandru Elisei
2021-02-17 16:46         ` Andre Przywara
2021-02-22 10:23           ` Andre Przywara
2021-02-22 15:01             ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 02/21] hw/serial: Use device abstraction for FDT generator function Andre Przywara
2021-02-11 12:05   ` Alexandru Elisei
2021-02-11 17:45     ` Andre Przywara
2020-12-10 14:28 ` [PATCH kvmtool 03/21] ioport: Retire .generate_fdt_node functionality Andre Przywara
2021-02-11 14:05   ` Alexandru Elisei
2021-02-17 15:54     ` Andre Przywara
2021-02-17 16:06       ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 04/21] mmio: Extend handling to include ioport emulation Andre Przywara
2021-02-11 16:10   ` Alexandru Elisei
2021-02-17 17:43     ` Andre Przywara
2021-02-22 15:50       ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 05/21] hw/i8042: Clean up data types Andre Przywara
2021-02-11 16:55   ` Alexandru Elisei
2021-02-17 17:46     ` Andre Przywara
2020-12-10 14:28 ` [PATCH kvmtool 06/21] hw/i8042: Refactor trap handler Andre Przywara
2021-02-11 17:23   ` Alexandru Elisei
2021-02-18 10:34     ` Andre Przywara
2021-02-18 11:17       ` Alexandru Elisei
2021-02-18 11:48         ` Andre Przywara
2021-02-22 16:03           ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 07/21] hw/i8042: Switch to new trap handlers Andre Przywara
2021-02-12 10:41   ` Alexandru Elisei
2021-02-18 12:09     ` Andre Przywara
2021-02-22 16:19       ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 08/21] x86/ioport: Refactor " Andre Przywara
2021-02-12 11:14   ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 09/21] x86/ioport: Switch to new " Andre Przywara
2021-02-12 11:27   ` Alexandru Elisei
2021-02-18 14:05     ` Andre Przywara
2020-12-10 14:28 ` [PATCH kvmtool 10/21] hw/rtc: Refactor " Andre Przywara
2021-02-12 11:56   ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 11/21] hw/rtc: Switch to new trap handler Andre Przywara
2021-02-12 12:02   ` Alexandru Elisei
2020-12-10 14:28 ` [PATCH kvmtool 12/21] hw/vesa: Switch trap handling to use MMIO handler Andre Przywara
2021-02-12 17:50   ` Alexandru Elisei
2020-12-10 14:29 ` [PATCH kvmtool 13/21] hw/serial: Refactor trap handler Andre Przywara
2021-02-16 14:22   ` Alexandru Elisei
2021-02-18 14:41     ` Andre Przywara
2021-02-22 17:40       ` Alexandru Elisei
2021-02-24 14:54         ` Andre Przywara
2020-12-10 14:29 ` [PATCH kvmtool 14/21] hw/serial: Switch to new trap handlers Andre Przywara
2021-02-16 14:31   ` Alexandru Elisei
2020-12-10 14:29 ` [PATCH kvmtool 15/21] vfio: Refactor ioport trap handler Andre Przywara
2021-02-16 14:47   ` Alexandru Elisei
2021-02-18 15:51     ` Andre Przywara
2020-12-10 14:29 ` [PATCH kvmtool 16/21] vfio: Switch to new ioport trap handlers Andre Przywara
2021-02-16 14:52   ` Alexandru Elisei
2020-12-10 14:29 ` [PATCH kvmtool 17/21] virtio: Switch trap handling to use MMIO handler Andre Przywara
2021-02-16 17:03   ` Alexandru Elisei
2021-02-18 16:13     ` Andre Przywara
2020-12-10 14:29 ` [PATCH kvmtool 18/21] pci: " Andre Przywara
2021-02-17 15:14   ` Alexandru Elisei
2020-12-10 14:29 ` [PATCH kvmtool 19/21] Remove ioport specific routines Andre Przywara
2021-02-17 15:49   ` Alexandru Elisei
2021-02-17 16:11     ` Alexandru Elisei
2021-02-18 16:34       ` Andre Przywara
2020-12-10 14:29 ` [PATCH kvmtool 20/21] hw/serial: ARM/arm64: Use MMIO at higher addresses Andre Przywara
2021-02-17 16:48   ` Alexandru Elisei
2021-02-18 12:18     ` Alexandru Elisei
2021-02-18 16:38       ` Andre Przywara
2020-12-10 14:29 ` [PATCH kvmtool 21/21] hw/rtc: " Andre Przywara
2021-02-18 13:33   ` Alexandru Elisei
2021-02-18 16:41     ` Andre Przywara
2021-02-10 17:44 ` [PATCH kvmtool 00/21] Unify I/O port and MMIO trap handling Alexandru Elisei

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