[PATCH v16 29/45] KVM: arm64: CCA: Support runtime faulting of memory
Suzuki K Poulose
suzuki.poulose at arm.com
Wed Aug 12 08:40:09 PDT 2026
On 12/08/2026 15:06, Catalin Marinas wrote:
> On Wed, Aug 12, 2026 at 10:01:48AM +0100, Suzuki K Poulose wrote:
>> On 11/08/2026 16:42, Catalin Marinas wrote:
>>> On Mon, Aug 03, 2026 at 02:43:45PM +0100, Steven Price wrote:
>>>> At runtime if the realm guest accesses memory which hasn't yet been
>>>> mapped then KVM needs to either populate the region or fault the guest.
>>>>
>>>> For memory in the lower (protected) region of IPA a fresh page is
>>>> provided to the RMM which will zero the contents. For memory in the
>>>> upper (shared) region of IPA, the memory from the memslot is mapped
>>>> into the realm VM non secure.
>>>
>>> Is this still true with in-place guestmem conversion?
>>>
>>>> @@ -1693,7 +1709,14 @@ static int gmem_abort(const struct kvm_s2_fault_desc *s2fd)
>>>> kvm_fault_lock(kvm);
>>>> if (mmu_invalidate_retry(kvm, mmu_seq)) {
>>>> ret = -EAGAIN;
>>>> - goto out_unlock;
>>>> + goto out_release_page;
>>>> + }
>>>> +
>>>> + if (kvm_is_realm(kvm)) {
>>>> + prot &= ~KVM_PGTABLE_PROT_X;
>>>> + ret = realm_map_ipa(kvm, s2fd->fault_ipa, pfn,
>>>> + PAGE_SIZE, prot, memcache);
>>>> + goto out_release_page;
>>>> }
>>>
>>> [...]
>>>
>>>> +int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa,
>>>> + kvm_pfn_t pfn, unsigned long map_size,
>>>> + enum kvm_pgtable_prot prot,
>>>> + struct kvm_mmu_memory_cache *memcache)
>>>> +{
>>>> + struct realm *realm = &kvm->arch.realm;
>>>> +
>>>> + ipa = ALIGN_DOWN(ipa, map_size);
>>>> + if (!kvm_realm_is_private_address(realm, ipa)) {
>>>> + return realm_map_non_secure(kvm, ipa, pfn, map_size, prot,
>>>> + memcache);
>>>> + }
>>>> +
>>>> + /* It's impossible to map protected pages read-only. */
>>>> + if (WARN_ON(!(prot & KVM_PGTABLE_PROT_W)))
>>>> + return -EFAULT;
>>>> + return realm_map_protected(kvm, ipa, pfn, map_size, memcache);
>>>> +}
>>>
>>> I was trying to understand (with the help of some LLMs) to understand
>>> whether we can end up on the do_gpf() path as a result of VMM actions.
>>> The above kvm_realm_is_private_address() only checks for the IPA but
>>> does not check against guestmem if the page is truly private. I probably
>>> miss something but the scenario would be something like:
>>>
>>> 1. VMM creates the gmem region with GUEST_MEMFD_FLAG_MMAP |
>>> GUEST_MEMFD_FLAG_INIT_SHARED, mmap()able and GUP-pinnable
>>>
>>> 2. VMM starts an O_DIRECT write() from that mapping; the block layer
>>> FOLL_PINs the shared folio
>>>
>>> 3. VMM runs a vCPU so the realm touches the protected-IPA alias of the
>>> same gfn. gmem_abort() delegates the pinned, still-shared page to
>>> the RMM
>>>
>>> 4. The in-flight I/O then reads the now-Realm page from the kernel
>>> linear map. That access takes a GPF at EL1, so do_gpf() ->
>>> die_kernel_fault()
>>
>> This is correct. The fundamental issue is that we have a disconnect
>> between the "gmem attribute" changes (to private/shared) and the
>> RIPAS and this is something we want to fix.
>>
>> e.g., the KVM CCA driver sets the entire DRAM to RIPAS_RAM for
>> the Realm before ACTIVATION and we expect that the VMM changes
>> the gmem to PRIVATE. They both are not in sync. his is something
>> we were discussing the other day with Aneesh.
>>
>> Once they are in sync, we are protected. If the RIPAS=EMPTY
>> (gmem=shared) a stage2 fault doesn't come to the Host.
>>
>> If the RIPAS=RAM, the gmem is private and there are no usespace
>> mappings.
>>
>> The reason why it is disconnected at the moment is due to the
>> weird semantics for Guest triggered conversions in CCA
>> i.e., Realm requests via RSI_IPA_STATE_SET, triggering a RIPAS_CHANGE
>> exit to the KVM.
>>
>> The KVM exits to VMM with MEMORY_FAULT_EXIT and the VMM can service this
>> by invoking GMEM(SET_ATTRIBUTES2).
>
> I guess a buggy or malicious VMM may skip the gmem attribute setting and
> simply resume the guest. Currently we can end up with SET_RIPAS
> irrespective of what the VMM did. So at this point maybe we need to
> check that the gmem attribute was actually changed before handling the
> pending RMI requests.
>
> The other place to check the gmem status is when handling the
> gmem_abort().
We did have that check in v14 [0] and forcing a MEMORY_FAULT_EXIT. I
thought we didn't need it with in-place conversion, but looks like that was
wrong call.
[0]
https://lore.kernel.org/all/20260513131757.116630-30-steven.price@arm.com/
>
> I wonder whether we can have any races with either of these if multiple
> vCPUs toggle the RIPAS state between RAM and EMPTY and we need both
> places (the RIPAS_CHANGE exit and the actual stage 2 fault).
>
>> But, the KVM needs to invoke the
>> RMI_RTT_SET_RIPAS in the context of the "vcpu", which we don't have
>> from the "kvm" context. I guess we can fix it by running through the
>> vcpus and find the matching one with the "ipa" range and the "ripas".
>
> Or multiple vcpus? Does the spec allow multiple RIPAS_CHANGE requests
> for the same IPA? If yes, we probably need to clear all.
Ideally, a guest shouldn't pass overlapping requests to the host. Host
could reject either of them, irrespective of the order we got it.
I will get this clarified in the spec.
Cheers
Suzuki
More information about the linux-arm-kernel
mailing list