Index | Thread | Search

From:
hshoexer <hshoexer@yerbouti.franken.de>
Subject:
Re: SEV-SNP: bus_dma(9): Rescind and claim DMA bounce buffer
To:
tech@openbsd.org
Date:
Thu, 24 Sep 2026 20:43:15 +0200

Download raw body.

Thread
On Thu, Sep 24, 2026 at 07:33:39PM +0200, Mark Kettenis wrote:
> > Date: Thu, 24 Sep 2026 18:14:41 +0200
> > From: hshoexer <hshoexer@yerbouti.franken.de>
> > 
> > Hi,
> > 
> > when creating DMA maps, rescind DMA bounce buffer pages to the
> > hypervisor.  When destroying DMA maps, claim these pages back from
> > the hypervisor.
> > 
> > ok?
> 
> Sorry, too much jargon I'm not familliar with.  Can you explain what
> does actually does?

sure:

With SEV and SEV-ES:  For pages to be shared with the hypervisor
the guest maps them without the crypt bit (PMAP_NOCRYPT).  That's
what we do when setting up pages to be used as bounce buffers.
However, the hypervisor can still access "private" pages, e.g. pages
that are mapped encrypted by setting the crypt bit in the PTE.  This
corrupts the cipher text, pages are not integrity protected.  SEV
and SEV-ES only provide "privacy".

SEV-SNP provides integrity protection.  All physcal pages are managed
with the so called Reverse Mapping Table (RMP).  The MMU not only
uses the information from the page table but also from the RMP.

Pages have to be either assigned to the Hypervisor/Host OS or the
guest (VM).  Note: There are more possible page "owners", I'm
simplifying a bit.

When the hypervisor touches a guest owned page, #GP is raised.  When
a page is owned by the hypervisor, the guest is allowed to touch
this page as long as it is mapped unencrypted.  This is what we
want to do for bounce buffering.

When the hypervisor forcefully withdraws a page from the guest, the
page is "invalidated".  When the guest touches such a page, a #VC
trap is raised in the guest.  This allows the guest to detect this
"corruption".  That's the integrity protection, SEV-SNP provides.

On guest launch the guest firmware -- SEV-SNP enable OVMF for
qemu/KVM -- "claims" all pages assigned to the VM with these steps:

1) Remove the mapping for unencrypted access, i.e. map it encrypted
2) Request the hypervisor to set "assigned" to "guest owned", using
   the GHCB protocol function "page stage change"
3) "validate" the page using the pvalidate instruction.

Afte  that these pages are marked in the RMP to be owned by the
guest, the hypervisor can not access these pages anymore without
raising #GP.

To share pages with the hypervisor the -- for bounce buffering --
the guest "rescinds" pages back to the hypervisor with these three
steps:

1) Set "validate" in the RMP to 0 using pvalidate instruction.
2) Request the hypervisor to set "assigned" in the RMP to  "hypervisor
   owned", using the GHCB protocol "page state change"
3) Establish a mapping with the C-bit cleared; with this mapping
   the page can be accessed unencrypted.

So, when setting up bounce buffers on dmamap creation, the guest
"rescinds" pages.  When destroying the dmamap the guest "claims"
the pages again.  Claim and resincd is implemented in diff #1.

Naming is hard.

Take care,
HJ.

> > Take care,
> > HJ.
> > ---
> >  sys/arch/amd64/amd64/bus_dma.c | 5 +++++
> >  1 file changed, 5 insertions(+)
> > 
> > diff --git a/sys/arch/amd64/amd64/bus_dma.c b/sys/arch/amd64/amd64/bus_dma.c
> > index f4efff95a18..2e69319739c 100644
> > --- a/sys/arch/amd64/amd64/bus_dma.c
> > +++ b/sys/arch/amd64/amd64/bus_dma.c
> > @@ -100,6 +100,7 @@
> >  #endif
> >  
> >  #include <machine/bus.h>
> > +#include <machine/snp.h>
> >  
> >  #include <uvm/uvm_extern.h>
> >  
> > @@ -255,6 +256,8 @@ _bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
> >  		return (ENOMEM);
> >  	}
> >  
> > +	snp_rescind_pages(&mlist);
> > +
> >  	sva = va;
> >  	ssize = sz;
> >  	pgnext = TAILQ_FIRST(&mlist);
> > @@ -269,6 +272,7 @@ _bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
> >  			map->_dm_npages = 0;
> >  			km_free((void *)sva, ssize, &kv_any, &kp_none);
> >  			free(map, M_DEVBUF, mapsize);
> > +			snp_claim_pages(&mlist);
> >  			uvm_pglistfree(&mlist);
> >  			return (ENOMEM);
> >  		}
> > @@ -307,6 +311,7 @@ _bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map)
> >  		for (pg = map->_dm_pages; map->_dm_npages--; pg++) {
> >  			TAILQ_INSERT_TAIL(&mlist, *pg, pageq);
> >  		}
> > +		snp_claim_pages(&mlist);
> >  		uvm_pglistfree(&mlist);
> >  	}
> >  
> > -- 
> > 2.47.3
> > 
> >