Re: [PATCH 9/9] arm64: Retrieve stolen time as paravirtualized guest

From: Zenghui Yu
Date: Tue Aug 13 2019 - 02:12:13 EST


On 2019/8/12 18:39, Steven Price wrote:
On 09/08/2019 14:51, Zenghui Yu wrote:
[...]
Hi Steven,

Since userspace is not involved yet (right?), no one will create the
PV_TIME device for guest (and no one will specify the IPA of the shared
stolen time region), and I guess we will get a "not supported" error
here.

So what should we do if we want to test this series now? Any userspace
tools? If no, do you have any plans for userspace developing? ;-)

At the moment I have the following patch to kvmtool which creates the
PV_TIME device - this isn't in a state to go upstream, and Marc has
asked that I rework the memory allocation, so this will need to change.

It's a little ugly as it simply reserves the first page of RAM to use
for the PV time structures.

Thanks for sharing the code. It's good enough to show what is required
in user-space.

(I'm not familiar with kvmtool. I will first take some time to move the
steal time part to Qemu and see what will happen.)


Thanks,
zenghui

----8<----
diff --git a/Makefile b/Makefile
index 3862112..a79956b 100644
--- a/Makefile
+++ b/Makefile
@@ -158,7 +158,7 @@ endif
# ARM
OBJS_ARM_COMMON := arm/fdt.o arm/gic.o arm/gicv2m.o arm/ioport.o \
arm/kvm.o arm/kvm-cpu.o arm/pci.o arm/timer.o \
- arm/pmu.o
+ arm/pmu.o arm/pvtime.o
HDRS_ARM_COMMON := arm/include
ifeq ($(ARCH), arm)
DEFINES += -DCONFIG_ARM
diff --git a/arm/fdt.c b/arm/fdt.c
index c80e6da..19eccbc 100644
--- a/arm/fdt.c
+++ b/arm/fdt.c
@@ -119,6 +119,7 @@ static int setup_fdt(struct kvm *kvm)
/* Create new tree without a reserve map */
_FDT(fdt_create(fdt, FDT_MAX_SIZE));
+ _FDT(fdt_add_reservemap_entry(fdt, kvm->arch.memory_guest_start, 4096));
_FDT(fdt_finish_reservemap(fdt));
/* Header */
diff --git a/arm/kvm.c b/arm/kvm.c
index 1f85fc6..8bbfef1 100644
--- a/arm/kvm.c
+++ b/arm/kvm.c
@@ -11,6 +11,8 @@
#include <linux/kvm.h>
#include <linux/sizes.h>
+int pvtime_create(struct kvm *kvm);
+
struct kvm_ext kvm_req_ext[] = {
{ DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
{ DEFINE_KVM_EXT(KVM_CAP_ONE_REG) },
@@ -86,6 +88,10 @@ void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
/* Create the virtual GIC. */
if (gic__create(kvm, kvm->cfg.arch.irqchip))
die("Failed to create virtual GIC");
+
+ /* Setup PV time */
+ if (pvtime_create(kvm))
+ die("Failed to initialise PV time");
}
#define FDT_ALIGN SZ_2M
diff --git a/arm/pvtime.c b/arm/pvtime.c
new file mode 100644
index 0000000..abcaab3
--- /dev/null
+++ b/arm/pvtime.c
@@ -0,0 +1,77 @@
+#include "kvm/kvm.h"
+
+#define KVM_DEV_TYPE_ARM_PV_TIME (KVM_DEV_TYPE_ARM_VGIC_ITS+2)
+
+/* Device Control API: PV_TIME */
+#define KVM_DEV_ARM_PV_TIME_PADDR 0
+#define KVM_DEV_ARM_PV_TIME_FREQUENCY 3
+
+#define KVM_DEV_ARM_PV_TIME_ST 0
+#define KVM_DEV_ARM_PV_TIME_LPT 1
+
+static int pvtime_fd;
+
+int pvtime_create(struct kvm *kvm);
+
+int pvtime_create(struct kvm *kvm)
+{
+ int err;
+ u64 lpt_paddr = 0x10000000;
+ u64 st_paddr = lpt_paddr + 4096;
+ u32 frequency = 100 * 1000 * 1000;
+
+ printf("lpt_paddr=%llx\n", lpt_paddr);
+
+ struct kvm_create_device pvtime_device = {
+ .type = KVM_DEV_TYPE_ARM_PV_TIME,
+ .flags = 0,
+ };
+
+ err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &pvtime_device);
+ if (err) {
+ printf("Failed to create PV device\n");
+ return 0;
+ }
+
+ pvtime_fd = pvtime_device.fd;
+
+ struct kvm_device_attr lpt_base = {
+ .group = KVM_DEV_ARM_PV_TIME_PADDR,
+ .attr = KVM_DEV_ARM_PV_TIME_LPT,
+ .addr = (u64)(unsigned long)&lpt_paddr
+ };
+ struct kvm_device_attr st_base = {
+ .group = KVM_DEV_ARM_PV_TIME_PADDR,
+ .attr = KVM_DEV_ARM_PV_TIME_ST,
+ .addr = (u64)(unsigned long)&st_paddr
+ };
+
+ struct kvm_device_attr lpt_freq = {
+ .group = KVM_DEV_ARM_PV_TIME_FREQUENCY,
+ .attr = KVM_DEV_ARM_PV_TIME_LPT,
+ .addr = (u64)(unsigned long)&frequency
+ };
+
+ err = ioctl(pvtime_fd, KVM_SET_DEVICE_ATTR, &lpt_base);
+ if (err) {
+ perror("ioctl lpt_base failed");
+ printf("Ignoring LPT...\n");
+ }
+ err = ioctl(pvtime_fd, KVM_SET_DEVICE_ATTR, &st_base);
+ if (err) {
+ perror("ioctl st_base failed");
+ goto out_err;
+ }
+ err = ioctl(pvtime_fd, KVM_SET_DEVICE_ATTR, &lpt_freq);
+ if (err) {
+ perror("ioctl lpt_freq failed");
+ printf("Ignoring LPT...\n");
+ }
+
+ printf("PV time setup\n");
+
+ return 0;
+out_err:
+ close(pvtime_fd);
+ return err;
+}