Thread (233 messages) 233 messages, 15 authors, 2021-10-28

RE: [RFC] /dev/ioasid uAPI proposal

From: "Tian, Kevin" <kevin.tian@intel.com>
Date: 2021-06-09 02:49:41
Also in: linux-iommu, lkml

From: Alex Williamson <redacted>
Sent: Wednesday, June 9, 2021 2:47 AM

On Tue, 8 Jun 2021 15:44:26 +0200
Paolo Bonzini [off-list ref] wrote:
quoted
On 08/06/21 15:15, Jason Gunthorpe wrote:
quoted
On Tue, Jun 08, 2021 at 09:56:09AM +0200, Paolo Bonzini wrote:
quoted
quoted
quoted
Alternatively you can add a KVM_DEV_IOASID_{ADD,DEL} pair of
ioctls. But it
quoted
quoted
quoted
quoted
quoted
seems useless complication compared to just using what we have
now, at least
quoted
quoted
quoted
quoted
quoted
while VMs only use IOASIDs via VFIO.
The simplest is KVM_ENABLE_WBINVD(<fd security proof>) and be
done
quoted
quoted
quoted
quoted
with it.
Even if we were to relax wbinvd access to any device (capable of
no-snoop or not) in any IOMMU configuration (blocking no-snoop or not),
I think as soon as we say "proof" is required to gain this access then
that proof should be ongoing for the life of the access.

That alone makes this more than a "I want this feature, here's my
proof", one-shot ioctl.  Like the groupfd enabling a path for KVM to
ask if that group is non-coherent and holding a group reference to
prevent the group from being used to authorize multiple KVM instances,
the ioasidfd proof would need to minimally validate that devices are
present and provide some reference to enforce that model as ongoing, or
notifier to indicate an end of that authorization.  I don't think we
can simplify that out of the equation or we've essentially invalidated
that the proof is really required.
quoted
quoted
quoted
The simplest one is KVM_DEV_VFIO_GROUP_ADD/DEL, that already
exists and also
quoted
quoted
quoted
covers hot-unplug.  The second simplest one is
KVM_DEV_IOASID_ADD/DEL.
quoted
quoted
This isn't the same thing, this is back to trying to have the kernel
set policy for userspace.
If you want a userspace policy then there would be three states:

* WBINVD enabled because a WBINVD-enabled VFIO device is attached.

* WBINVD potentially enabled but no WBINVD-enabled VFIO device
attached
quoted
* WBINVD forcefully disabled

KVM_DEV_VFIO_GROUP_ADD/DEL can still be used to distinguish the first
two.  Due to backwards compatibility, those two describe the default
behavior; disabling wbinvd can be done easily with a new sub-ioctl of
KVM_ENABLE_CAP and doesn't require any security proof.
That seems like a good model, use the kvm-vfio device for the default
behavior and extend an existing KVM ioctl if QEMU still needs a way to
tell KVM to assume all DMA is coherent, regardless of what the kvm-vfio
device reports.

If feels like we should be able to support a backwards compatibility
mode using the vfio group, but I expect long term we'll want to
transition the kvm-vfio device from a groupfd to an ioasidfd.
quoted
The meaning of WBINVD-enabled is "won't return -ENXIO for the wbinvd
ioctl", nothing more nothing less.  If all VFIO devices are going to be
WBINVD-enabled, then that will reflect on KVM as well, and I won't have
anything to object if there's consensus on the device assignment side of
things that the wbinvd ioctl won't ever fail.
If we create the IOMMU vs device coherency matrix:

            \ Device supports
IOMMU blocks \   no-snoop
  no-snoop    \  yes | no  |
---------------+-----+-----+
           yes |  1  |  2  |
---------------+-----+-----+
           no  |  3  |  4  |
---------------+-----+-----+

DMA is always coherent in boxes {1,2,4} (wbinvd emulation is not
needed).  VFIO will currently always configure the IOMMU for {1,2} when
the feature is supported.  Boxes {3,4} are where we'll currently
emulate wbinvd.  The best we could do, not knowing the guest or
insights into the guest driver would be to only emulate wbinvd for {3}.

The majority of devices appear to report no-snoop support {1,3}, but
the claim is that it's mostly unused outside of GPUs, effectively {2,4}.
I'll speculate that most IOMMUs support enforcing coherency (amd, arm,
fsl unconditionally, intel conditionally) {1,2}.

I think that means we're currently operating primarily in Box {1},
which does not seem to lean towards unconditional wbinvd access with
device ownership.

I think we have a desire with IOASID to allow user policy to operate
certain devices in {3} and I think the argument there is that a
specific software enforced coherence sync is more efficient on the bus
than the constant coherence enforcement by the IOMMU.

I think that the disable mode Jason proposed is essentially just a way
to move a device from {3} to {4}, ie. the IOASID support or
configuration does not block no-snoop and the device claims to support
no-snoop, but doesn't use it.  How we'd determine this to be true for
a device without a crystal ball of driver development or hardware
errata that no-snoop transactions are not possible regardless of the
behavior of the enable bit, I'm not sure.  If we're operating a device
in {3}, but the device does not generate no-snoop transactions, then
presumably the guest driver isn't generating wbinvd instructions for us
to emulate, so where are the wbinvd instructions that this feature
would prevent being emulated coming from?  Thanks,
I'm writing v2 now. Below is what I captured from this discussion.
Please let me know whether it matches your thoughts:

- Keep existing kvm-vfio device with kernel-decided policy in short term, 
  i.e. 'disable' for 1/2 and 'enable' for 3/4. Jason still has different thought
  whether this should be an explicit wbinvd cmd, though;

- Long-term transition to ioasidfd (for non-vfio usage);

- As extension we want to support 'force-enable' (1->3 for performance
  reason) from user but not 'force-disable' (3->4, sounds meaningless 
  since if guest driver doesn't use wbinvd then keeping wbinvd emulation 
  doesn't hurt);

- To support 'force-enable' no need for additional KVM-side contract.
   It just relies on what kvm-vfio device reports, regardless of whether
   an 'enable' policy comes from kernel or user;

- 'force-enable' is supported through /dev/iommu (new name for
  /dev/ioasid);

- Qemu first calls IOMMU_GET_DEV_INFO(device_handle) to acquire 
  the default policy (enable vs. disable) for a device. This is the kernel 
  decision based on device no-snoop and iommu snoop control capability;

- If not specified, an newly-created IOASID follows the kernel policy.
  Alternatively, Qemu could explicitly mark an IOASID as non-coherent
  when IOMMU_ALLOC_IOASID;

- Attaching a non-snoop device which cannot be forced to snoop by 
  iommu to a coherent IOASID gets a failure, because a snoop-format 
  I/O page table causes error on such iommu;
  
- Devices attached to a non-coherent IOASID all use the no-snoop 
  format I/O page table, even when the iommu is capable of forcing 
  snoop;

- After IOASID is properly configured, Qemu then uses kvm-vfio device
  to notify KVM which calls vfio helper function to get coherent attribute
  per vfio_group. Because this attribute is kept in IOASID, we possibly
  need return the attribute to vfio when vfio_attach_ioasid. 

Last unclosed open. Jason, you dislike symbol_get in this contract per
earlier comment. As Alex explained, looks it's more about module
dependency which is orthogonal to how this contract is designed. What
is your opinion now?

Thanks
Kevin
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help