[PATCH 09/14] KVM: arm64: Trap & emulate the ITS VMAPP command

Sebastian Ene
2026-03-10T12:50:17Z

Parse the VMAPP command and extract the virtual pending
table address and the size of the table. When the command
has the valid bit set, share the memory that holds this
table with the hypervisor and track it in an array.
Unshare this from the hypervisor when the valid bit
is cleared.
Check if we need to do any shadow table updates
in case the vPE table is configured with an
indirect layout.

Signed-off-by: Sebastian Ene <sebastianene@google.com>
---
arch/arm64/kvm/hyp/nvhe/its_emulate.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/its_emulate.c b/arch/arm64/kvm/hyp/nvhe/its_emulate.c
index 722fe80dc2e5..7049d307a236 100644
--- a/arch/arm64/kvm/hyp/nvhe/its_emulate.c
+++ b/arch/arm64/kvm/hyp/nvhe/its_emulate.c
@@ -178,6 +178,26 @@ static int process_its_mapd(struct its_priv_state *its, struct its_cmd_block *cm
return track_pfn(its, base_pfn, num_pages, remove);
}

+static int process_its_vmapp(struct its_priv_state *its, struct its_cmd_block *cmd)
+{
+ bool remove = !(cmd->raw_cmd[2] & BIT(63));
+ phys_addr_t vpt_addr = cmd->raw_cmd[3] & GENMASK(51, 16);
+ u8 vpt_size = cmd->raw_cmd[3] & GENMASK(4, 0);
+ u32 vpe_id = (cmd->raw_cmd[1] & GENMASK(47, 32)) >> 32;
+ int num_pages;
+ u64 base_pfn;
+ int ret;
+
+ base_pfn = hyp_phys_to_pfn(vpt_addr);
+ num_pages = ALIGN(BIT((vpt_size + 1) >> 3), SZ_64K);
+
+ ret = check_table_update(its, vpe_id, GITS_BASER_TYPE_VCPU);
+ if (ret)
+ return ret;
+
+ return track_pfn(its, base_pfn, num_pages, remove);
+}
+
static int parse_its_cmdq(struct its_priv_state *its, int offset, ssize_t len)
{
struct its_cmd_block *cmd = its->cmd_hyp_base + offset;
@@ -191,6 +211,10 @@ static int parse_its_cmdq(struct its_priv_state *its, int offset, ssize_t len)
case GITS_CMD_MAPD:
ret = process_its_mapd(its, cmd);
break;
+
+ case GITS_CMD_VMAPP:
+ ret = process_its_vmapp(its, cmd);
+ break;
}

cmd++;
--
2.53.0.473.g4a7958ca14-goog