Re: [RFC PATCH 00/10] KVM: selftests: Add support for test-selectable ucall implementations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/10/21 17:46, Michael Roth wrote:
These patches are based on kvm/next, and are also available at:

   https://github.com/mdroth/linux/commits/sev-selftests-ucall-rfc1

Thanks, this is a nice implementation of the concept. I'll check s390 before the next merge window, as I intend to merge this and the SEV tests (which I have already confirmed to work; I haven't yet checked SEV-ES because it's a bit harder for me to install new kernels on the SEV-ES machine I have access to).

Paolo

== BACKGROUND ==

These patches are a prerequisite for adding selftest support for SEV guests
and possibly other confidential computing implementations in the future.
They were motivated by a suggestion Paolo made in response to the initial
SEV selftest RFC:

   https://lore.kernel.org/lkml/20211025035833.yqphcnf5u3lk4zgg@xxxxxxx/T/#m959b56f9fb4ae6ab973f6ab50fe3ddfacd7c5617

Since the changes touch multiple archs and ended up creating a bit more churn
than expected, I thought it would be a good idea to carve this out into a
separate standalone series for reviewers who may be more interested in the
ucall changes than anything SEV-related.

To summarize, x86 relies on a ucall based on using PIO intructions to generate
an exit to userspace and provide the GVA of a dynamically-allocated ucall
struct that resides in guest memory and contains information about how to
handle/interpret the exit. This doesn't work for SEV guests for 3 main reasons:

   1) The guest memory is generally encrypted during run-time, so the guest
      needs to ensure the ucall struct is allocated in shared memory.
   2) The guest page table is also encrypted, so the address would need to be a
      GPA instead of a GVA.
   3) The guest vCPU register may also be encrypted in the case of
      SEV-ES/SEV-SNP, so the approach of examining vCPU register state has
      additional requirements such as requiring guest code to implement a #VC
      handler that can provide the appropriate registers via a vmgexit.

To address these issues, the SEV selftest RFC1 patchset introduced a set of new
SEV-specific interfaces that closely mirrored the functionality of
ucall()/get_ucall(), but relied on a pre-allocated/static ucall buffer in
shared guest memory so it that guest code could pass messages/state to the host
by simply writing to this pre-arranged shared memory region and then generating
an exit to userspace (via a halt instruction).

Paolo suggested instead implementing support for test/guest-specific ucall
implementations that could be used as an alternative to the default PIO-based
ucall implementations as-needed based on test/guest requirements, while still
allowing for tests to use a common set interfaces like ucall()/get_ucall().

== OVERVIEW ==

This series implements the above functionality by introducing a new ucall_ops
struct that can be used to register a particular ucall implementation as need,
then re-implements x86/arm64/s390x in terms of the ucall_ops.

But for the purposes of introducing a new ucall_ops implementation appropriate
for SEV, there are a couple issues that resulted in the need for some additional
ucall interfaces as well:

   a) ucall() doesn't take a pointer to the ucall struct it modifies, so to make
      it work in the case of an implementation that relies a pre-allocated ucall
      struct in shared guest memory some sort of global lookup functionality
      would be needed to locate the appropriate ucall struct for a particular
      VM/vcpu combination, and this would need to be made accessible for use by
      the guest as well. guests would then need some way of determining what
      VM/vcpu identifiers they need to use to do the lookup, which to do reliably
      would likely require seeding the guest with those identifiers in advance,
      which is possible, but much more easily achievable by simply adding a
      ucall() alternative that accepts a pointer to the ucall struct for that
      particular VM/vcpu.

   b) get_ucall() *does* take a pointer to a ucall struct, but currently zeroes
      it out and uses it to copy the guest's ucall struct into. It *could* be
      re-purposed to handle the case where the pointer is an actual pointer to
      the ucall struct in shared guest memory, but that could cause problems
      since callers would need some idea of what the underlying ucall
      implementation expects. Ideally the interfaces would be agnostic to the
      ucall implementation.

So to address those issues, this series also allows ucall implementations to
optionally be extended to support a set of 'shared' ops that are used in the
following manner:

   host:
     uc_gva = ucall_shared_alloc()
     setup_vm_args(vm, uc_gva)

   guest:
     ucall_shared(uc_gva, ...)

   host:
     uget_ucall_shared(uc_gva, ...)

and then implements a new ucall implementation, ucall_ops_halt, based around
these shared interfaces and halt instructions.

While this doesn't really meet the initial goal of re-using the existing
ucall interfaces as-is, the hope is that these *_shared interfaces are
general enough to be re-usable things other than SEV, or at least improve on
code readability over the initial SEV-specific interfaces.

Any review/comments are greatly appreciated!

----------------------------------------------------------------
Michael Roth (10):
       kvm: selftests: move base kvm_util.h declarations to kvm_util_base.h
       kvm: selftests: move ucall declarations into ucall_common.h
       kvm: selftests: introduce ucall_ops for test/arch-specific ucall implementations
       kvm: arm64: selftests: use ucall_ops to define default ucall implementation
       (COMPILE-TESTED ONLY) kvm: s390: selftests: use ucall_ops to define default ucall implementation
       kvm: selftests: add ucall interfaces based around shared memory
       kvm: selftests: add ucall_shared ops for PIO
       kvm: selftests: introduce ucall implementation based on halt instructions
       kvm: selftests: add GUEST_SHARED_* macros for shared ucall implementations
       kvm: selftests: add ucall_test to test various ucall functionality

  tools/testing/selftests/kvm/.gitignore             |   1 +
  tools/testing/selftests/kvm/Makefile               |   5 +-
  .../testing/selftests/kvm/include/aarch64/ucall.h  |  18 +
  tools/testing/selftests/kvm/include/kvm_util.h     | 408 +--------------------
  .../testing/selftests/kvm/include/kvm_util_base.h  | 368 +++++++++++++++++++
  tools/testing/selftests/kvm/include/s390x/ucall.h  |  18 +
  tools/testing/selftests/kvm/include/ucall_common.h | 147 ++++++++
  tools/testing/selftests/kvm/include/x86_64/ucall.h |  19 +
  tools/testing/selftests/kvm/lib/aarch64/ucall.c    |  43 +--
  tools/testing/selftests/kvm/lib/s390x/ucall.c      |  45 +--
  tools/testing/selftests/kvm/lib/ucall_common.c     | 133 +++++++
  tools/testing/selftests/kvm/lib/x86_64/ucall.c     |  82 +++--
  tools/testing/selftests/kvm/ucall_test.c           | 182 +++++++++
  13 files changed, 982 insertions(+), 487 deletions(-)
  create mode 100644 tools/testing/selftests/kvm/include/aarch64/ucall.h
  create mode 100644 tools/testing/selftests/kvm/include/kvm_util_base.h
  create mode 100644 tools/testing/selftests/kvm/include/s390x/ucall.h
  create mode 100644 tools/testing/selftests/kvm/include/ucall_common.h
  create mode 100644 tools/testing/selftests/kvm/include/x86_64/ucall.h
  create mode 100644 tools/testing/selftests/kvm/lib/ucall_common.c
  create mode 100644 tools/testing/selftests/kvm/ucall_test.c






[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux