ANDROID: KVM: arm64: Increase size of FF-A buffer

As it turns out, the kernel's DMA code doesn't enforce the
SG_MAX_SEGMENTS limit on the number of elements in an sglist, which can
confuse the pKVM FF-A proxy which has a buffer sized to contain a
descriptor of at most SG_MAX_SEGMENTS constituents.

As the number of elements in an sglist doesn't seem to have an actual
upper bound, let's paper over the issue for now by increasing the size
of the pKVM buffer based on empirical 'measurements'. Longer term we
might need to make this value configurable on the kernel's cmdline, or
to rework the FF-A proxy to sanely handle large descriptors, although
this is not clear how at the time of writing.

Bug: 221256863
Signed-off-by: Quentin Perret <qperret@google.com>
Change-Id: If252f01bec8ae71c0fe1f7007a3ca7b037924c84
This commit is contained in:
Quentin Perret
2022-07-18 14:44:32 +00:00
parent 094905c877
commit a6b9536c10

View File

@@ -327,10 +327,27 @@ static inline unsigned long host_s2_pgtable_pages(void)
#define KVM_FFA_MBOX_NR_PAGES 1
/*
* Maximum number of consitutents allowed in a descriptor. This number is
* arbitrary, see comment below on SG_MAX_SEGMENTS in hyp_ffa_proxy_pages().
*/
#define KVM_FFA_MAX_NR_CONSTITUENTS 4096
static inline unsigned long hyp_ffa_proxy_pages(void)
{
size_t desc_max;
/*
* SG_MAX_SEGMENTS is supposed to bound the number of elements in an
* sglist, which should match the number of consituents in the
* corresponding FFA descriptor. As such, the EL2 buffer needs to be
* large enough to hold a descriptor with SG_MAX_SEGMENTS consituents
* at least. But the kernel's DMA code doesn't enforce the limit, and
* it is sometimes abused, so let's allow larger descriptors and hope
* for the best.
*/
BUILD_BUG_ON(KVM_FFA_MAX_NR_CONSTITUENTS < SG_MAX_SEGMENTS);
/*
* The hypervisor FFA proxy needs enough memory to buffer a fragmented
* descriptor returned from EL3 in response to a RETRIEVE_REQ call.
@@ -338,7 +355,7 @@ static inline unsigned long hyp_ffa_proxy_pages(void)
desc_max = sizeof(struct ffa_mem_region) +
sizeof(struct ffa_mem_region_attributes) +
sizeof(struct ffa_composite_mem_region) +
SG_MAX_SEGMENTS * sizeof(struct ffa_mem_region_addr_range);
KVM_FFA_MAX_NR_CONSTITUENTS * sizeof(struct ffa_mem_region_addr_range);
/* Plus a page each for the hypervisor's RX and TX mailboxes. */
return (2 * KVM_FFA_MBOX_NR_PAGES) + DIV_ROUND_UP(desc_max, PAGE_SIZE);