[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]

 



These patches are based on kvm/next, and are also available at:

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

== 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]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux