xref: /linux/tools/testing/selftests/kvm/lib/arm64/processor.c (revision 0e8863244ef5b7d4391816062fcc07ff49aa7dcf)
167730e6cSSean Christopherson // SPDX-License-Identifier: GPL-2.0
267730e6cSSean Christopherson /*
367730e6cSSean Christopherson  * AArch64 code
467730e6cSSean Christopherson  *
567730e6cSSean Christopherson  * Copyright (C) 2018, Red Hat, Inc.
667730e6cSSean Christopherson  */
767730e6cSSean Christopherson 
867730e6cSSean Christopherson #include <linux/compiler.h>
967730e6cSSean Christopherson #include <assert.h>
1067730e6cSSean Christopherson 
1167730e6cSSean Christopherson #include "guest_modes.h"
1267730e6cSSean Christopherson #include "kvm_util.h"
1367730e6cSSean Christopherson #include "processor.h"
1467730e6cSSean Christopherson #include "ucall_common.h"
1567730e6cSSean Christopherson 
1667730e6cSSean Christopherson #include <linux/bitfield.h>
1767730e6cSSean Christopherson #include <linux/sizes.h>
1867730e6cSSean Christopherson 
1967730e6cSSean Christopherson #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
2067730e6cSSean Christopherson 
2167730e6cSSean Christopherson static vm_vaddr_t exception_handlers;
2267730e6cSSean Christopherson 
page_align(struct kvm_vm * vm,uint64_t v)2367730e6cSSean Christopherson static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
2467730e6cSSean Christopherson {
2567730e6cSSean Christopherson 	return (v + vm->page_size) & ~(vm->page_size - 1);
2667730e6cSSean Christopherson }
2767730e6cSSean Christopherson 
pgd_index(struct kvm_vm * vm,vm_vaddr_t gva)2867730e6cSSean Christopherson static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
2967730e6cSSean Christopherson {
3067730e6cSSean Christopherson 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
3167730e6cSSean Christopherson 	uint64_t mask = (1UL << (vm->va_bits - shift)) - 1;
3267730e6cSSean Christopherson 
3367730e6cSSean Christopherson 	return (gva >> shift) & mask;
3467730e6cSSean Christopherson }
3567730e6cSSean Christopherson 
pud_index(struct kvm_vm * vm,vm_vaddr_t gva)3667730e6cSSean Christopherson static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva)
3767730e6cSSean Christopherson {
3867730e6cSSean Christopherson 	unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift;
3967730e6cSSean Christopherson 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
4067730e6cSSean Christopherson 
4167730e6cSSean Christopherson 	TEST_ASSERT(vm->pgtable_levels == 4,
4267730e6cSSean Christopherson 		"Mode %d does not have 4 page table levels", vm->mode);
4367730e6cSSean Christopherson 
4467730e6cSSean Christopherson 	return (gva >> shift) & mask;
4567730e6cSSean Christopherson }
4667730e6cSSean Christopherson 
pmd_index(struct kvm_vm * vm,vm_vaddr_t gva)4767730e6cSSean Christopherson static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva)
4867730e6cSSean Christopherson {
4967730e6cSSean Christopherson 	unsigned int shift = (vm->page_shift - 3) + vm->page_shift;
5067730e6cSSean Christopherson 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
5167730e6cSSean Christopherson 
5267730e6cSSean Christopherson 	TEST_ASSERT(vm->pgtable_levels >= 3,
5367730e6cSSean Christopherson 		"Mode %d does not have >= 3 page table levels", vm->mode);
5467730e6cSSean Christopherson 
5567730e6cSSean Christopherson 	return (gva >> shift) & mask;
5667730e6cSSean Christopherson }
5767730e6cSSean Christopherson 
pte_index(struct kvm_vm * vm,vm_vaddr_t gva)5867730e6cSSean Christopherson static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
5967730e6cSSean Christopherson {
6067730e6cSSean Christopherson 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
6167730e6cSSean Christopherson 	return (gva >> vm->page_shift) & mask;
6267730e6cSSean Christopherson }
6367730e6cSSean Christopherson 
use_lpa2_pte_format(struct kvm_vm * vm)6467730e6cSSean Christopherson static inline bool use_lpa2_pte_format(struct kvm_vm *vm)
6567730e6cSSean Christopherson {
6667730e6cSSean Christopherson 	return (vm->page_size == SZ_4K || vm->page_size == SZ_16K) &&
6767730e6cSSean Christopherson 	    (vm->pa_bits > 48 || vm->va_bits > 48);
6867730e6cSSean Christopherson }
6967730e6cSSean Christopherson 
addr_pte(struct kvm_vm * vm,uint64_t pa,uint64_t attrs)7067730e6cSSean Christopherson static uint64_t addr_pte(struct kvm_vm *vm, uint64_t pa, uint64_t attrs)
7167730e6cSSean Christopherson {
7267730e6cSSean Christopherson 	uint64_t pte;
7367730e6cSSean Christopherson 
7467730e6cSSean Christopherson 	if (use_lpa2_pte_format(vm)) {
75d8d78398SRaghavendra Rao Ananta 		pte = pa & PTE_ADDR_MASK_LPA2(vm->page_shift);
76d8d78398SRaghavendra Rao Ananta 		pte |= FIELD_GET(GENMASK(51, 50), pa) << PTE_ADDR_51_50_LPA2_SHIFT;
77d8d78398SRaghavendra Rao Ananta 		attrs &= ~PTE_ADDR_51_50_LPA2;
7867730e6cSSean Christopherson 	} else {
79d8d78398SRaghavendra Rao Ananta 		pte = pa & PTE_ADDR_MASK(vm->page_shift);
8067730e6cSSean Christopherson 		if (vm->page_shift == 16)
81d8d78398SRaghavendra Rao Ananta 			pte |= FIELD_GET(GENMASK(51, 48), pa) << PTE_ADDR_51_48_SHIFT;
8267730e6cSSean Christopherson 	}
8367730e6cSSean Christopherson 	pte |= attrs;
8467730e6cSSean Christopherson 
8567730e6cSSean Christopherson 	return pte;
8667730e6cSSean Christopherson }
8767730e6cSSean Christopherson 
pte_addr(struct kvm_vm * vm,uint64_t pte)8867730e6cSSean Christopherson static uint64_t pte_addr(struct kvm_vm *vm, uint64_t pte)
8967730e6cSSean Christopherson {
9067730e6cSSean Christopherson 	uint64_t pa;
9167730e6cSSean Christopherson 
9267730e6cSSean Christopherson 	if (use_lpa2_pte_format(vm)) {
93d8d78398SRaghavendra Rao Ananta 		pa = pte & PTE_ADDR_MASK_LPA2(vm->page_shift);
94d8d78398SRaghavendra Rao Ananta 		pa |= FIELD_GET(PTE_ADDR_51_50_LPA2, pte) << 50;
9567730e6cSSean Christopherson 	} else {
96d8d78398SRaghavendra Rao Ananta 		pa = pte & PTE_ADDR_MASK(vm->page_shift);
9767730e6cSSean Christopherson 		if (vm->page_shift == 16)
98d8d78398SRaghavendra Rao Ananta 			pa |= FIELD_GET(PTE_ADDR_51_48, pte) << 48;
9967730e6cSSean Christopherson 	}
10067730e6cSSean Christopherson 
10167730e6cSSean Christopherson 	return pa;
10267730e6cSSean Christopherson }
10367730e6cSSean Christopherson 
ptrs_per_pgd(struct kvm_vm * vm)10467730e6cSSean Christopherson static uint64_t ptrs_per_pgd(struct kvm_vm *vm)
10567730e6cSSean Christopherson {
10667730e6cSSean Christopherson 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
10767730e6cSSean Christopherson 	return 1 << (vm->va_bits - shift);
10867730e6cSSean Christopherson }
10967730e6cSSean Christopherson 
ptrs_per_pte(struct kvm_vm * vm)11067730e6cSSean Christopherson static uint64_t __maybe_unused ptrs_per_pte(struct kvm_vm *vm)
11167730e6cSSean Christopherson {
11267730e6cSSean Christopherson 	return 1 << (vm->page_shift - 3);
11367730e6cSSean Christopherson }
11467730e6cSSean Christopherson 
virt_arch_pgd_alloc(struct kvm_vm * vm)11567730e6cSSean Christopherson void virt_arch_pgd_alloc(struct kvm_vm *vm)
11667730e6cSSean Christopherson {
11767730e6cSSean Christopherson 	size_t nr_pages = page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size;
11867730e6cSSean Christopherson 
11967730e6cSSean Christopherson 	if (vm->pgd_created)
12067730e6cSSean Christopherson 		return;
12167730e6cSSean Christopherson 
12267730e6cSSean Christopherson 	vm->pgd = vm_phy_pages_alloc(vm, nr_pages,
12367730e6cSSean Christopherson 				     KVM_GUEST_PAGE_TABLE_MIN_PADDR,
12467730e6cSSean Christopherson 				     vm->memslots[MEM_REGION_PT]);
12567730e6cSSean Christopherson 	vm->pgd_created = true;
12667730e6cSSean Christopherson }
12767730e6cSSean Christopherson 
_virt_pg_map(struct kvm_vm * vm,uint64_t vaddr,uint64_t paddr,uint64_t flags)12867730e6cSSean Christopherson static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
12967730e6cSSean Christopherson 			 uint64_t flags)
13067730e6cSSean Christopherson {
131d8d78398SRaghavendra Rao Ananta 	uint8_t attr_idx = flags & (PTE_ATTRINDX_MASK >> PTE_ATTRINDX_SHIFT);
132d8d78398SRaghavendra Rao Ananta 	uint64_t pg_attr;
13367730e6cSSean Christopherson 	uint64_t *ptep;
13467730e6cSSean Christopherson 
13567730e6cSSean Christopherson 	TEST_ASSERT((vaddr % vm->page_size) == 0,
13667730e6cSSean Christopherson 		"Virtual address not on page boundary,\n"
13767730e6cSSean Christopherson 		"  vaddr: 0x%lx vm->page_size: 0x%x", vaddr, vm->page_size);
13867730e6cSSean Christopherson 	TEST_ASSERT(sparsebit_is_set(vm->vpages_valid,
13967730e6cSSean Christopherson 		(vaddr >> vm->page_shift)),
14067730e6cSSean Christopherson 		"Invalid virtual address, vaddr: 0x%lx", vaddr);
14167730e6cSSean Christopherson 	TEST_ASSERT((paddr % vm->page_size) == 0,
14267730e6cSSean Christopherson 		"Physical address not on page boundary,\n"
14367730e6cSSean Christopherson 		"  paddr: 0x%lx vm->page_size: 0x%x", paddr, vm->page_size);
14467730e6cSSean Christopherson 	TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn,
14567730e6cSSean Christopherson 		"Physical address beyond beyond maximum supported,\n"
14667730e6cSSean Christopherson 		"  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
14767730e6cSSean Christopherson 		paddr, vm->max_gfn, vm->page_size);
14867730e6cSSean Christopherson 
14967730e6cSSean Christopherson 	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8;
15067730e6cSSean Christopherson 	if (!*ptep)
151d8d78398SRaghavendra Rao Ananta 		*ptep = addr_pte(vm, vm_alloc_page_table(vm),
152d8d78398SRaghavendra Rao Ananta 				 PGD_TYPE_TABLE | PTE_VALID);
15367730e6cSSean Christopherson 
15467730e6cSSean Christopherson 	switch (vm->pgtable_levels) {
15567730e6cSSean Christopherson 	case 4:
15667730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8;
15767730e6cSSean Christopherson 		if (!*ptep)
158d8d78398SRaghavendra Rao Ananta 			*ptep = addr_pte(vm, vm_alloc_page_table(vm),
159d8d78398SRaghavendra Rao Ananta 					 PUD_TYPE_TABLE | PTE_VALID);
16067730e6cSSean Christopherson 		/* fall through */
16167730e6cSSean Christopherson 	case 3:
16267730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8;
16367730e6cSSean Christopherson 		if (!*ptep)
164d8d78398SRaghavendra Rao Ananta 			*ptep = addr_pte(vm, vm_alloc_page_table(vm),
165d8d78398SRaghavendra Rao Ananta 					 PMD_TYPE_TABLE | PTE_VALID);
16667730e6cSSean Christopherson 		/* fall through */
16767730e6cSSean Christopherson 	case 2:
16867730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8;
16967730e6cSSean Christopherson 		break;
17067730e6cSSean Christopherson 	default:
17167730e6cSSean Christopherson 		TEST_FAIL("Page table levels must be 2, 3, or 4");
17267730e6cSSean Christopherson 	}
17367730e6cSSean Christopherson 
174d8d78398SRaghavendra Rao Ananta 	pg_attr = PTE_AF | PTE_ATTRINDX(attr_idx) | PTE_TYPE_PAGE | PTE_VALID;
175*c8631ea5SRaghavendra Rao Ananta 	if (!use_lpa2_pte_format(vm))
176*c8631ea5SRaghavendra Rao Ananta 		pg_attr |= PTE_SHARED;
177*c8631ea5SRaghavendra Rao Ananta 
178d8d78398SRaghavendra Rao Ananta 	*ptep = addr_pte(vm, paddr, pg_attr);
17967730e6cSSean Christopherson }
18067730e6cSSean Christopherson 
virt_arch_pg_map(struct kvm_vm * vm,uint64_t vaddr,uint64_t paddr)18167730e6cSSean Christopherson void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr)
18267730e6cSSean Christopherson {
18367730e6cSSean Christopherson 	uint64_t attr_idx = MT_NORMAL;
18467730e6cSSean Christopherson 
18567730e6cSSean Christopherson 	_virt_pg_map(vm, vaddr, paddr, attr_idx);
18667730e6cSSean Christopherson }
18767730e6cSSean Christopherson 
virt_get_pte_hva(struct kvm_vm * vm,vm_vaddr_t gva)18867730e6cSSean Christopherson uint64_t *virt_get_pte_hva(struct kvm_vm *vm, vm_vaddr_t gva)
18967730e6cSSean Christopherson {
19067730e6cSSean Christopherson 	uint64_t *ptep;
19167730e6cSSean Christopherson 
19267730e6cSSean Christopherson 	if (!vm->pgd_created)
19367730e6cSSean Christopherson 		goto unmapped_gva;
19467730e6cSSean Christopherson 
19567730e6cSSean Christopherson 	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
19667730e6cSSean Christopherson 	if (!ptep)
19767730e6cSSean Christopherson 		goto unmapped_gva;
19867730e6cSSean Christopherson 
19967730e6cSSean Christopherson 	switch (vm->pgtable_levels) {
20067730e6cSSean Christopherson 	case 4:
20167730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
20267730e6cSSean Christopherson 		if (!ptep)
20367730e6cSSean Christopherson 			goto unmapped_gva;
20467730e6cSSean Christopherson 		/* fall through */
20567730e6cSSean Christopherson 	case 3:
20667730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8;
20767730e6cSSean Christopherson 		if (!ptep)
20867730e6cSSean Christopherson 			goto unmapped_gva;
20967730e6cSSean Christopherson 		/* fall through */
21067730e6cSSean Christopherson 	case 2:
21167730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8;
21267730e6cSSean Christopherson 		if (!ptep)
21367730e6cSSean Christopherson 			goto unmapped_gva;
21467730e6cSSean Christopherson 		break;
21567730e6cSSean Christopherson 	default:
21667730e6cSSean Christopherson 		TEST_FAIL("Page table levels must be 2, 3, or 4");
21767730e6cSSean Christopherson 	}
21867730e6cSSean Christopherson 
21967730e6cSSean Christopherson 	return ptep;
22067730e6cSSean Christopherson 
22167730e6cSSean Christopherson unmapped_gva:
22267730e6cSSean Christopherson 	TEST_FAIL("No mapping for vm virtual address, gva: 0x%lx", gva);
22367730e6cSSean Christopherson 	exit(EXIT_FAILURE);
22467730e6cSSean Christopherson }
22567730e6cSSean Christopherson 
addr_arch_gva2gpa(struct kvm_vm * vm,vm_vaddr_t gva)22667730e6cSSean Christopherson vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
22767730e6cSSean Christopherson {
22867730e6cSSean Christopherson 	uint64_t *ptep = virt_get_pte_hva(vm, gva);
22967730e6cSSean Christopherson 
23067730e6cSSean Christopherson 	return pte_addr(vm, *ptep) + (gva & (vm->page_size - 1));
23167730e6cSSean Christopherson }
23267730e6cSSean Christopherson 
pte_dump(FILE * stream,struct kvm_vm * vm,uint8_t indent,uint64_t page,int level)23367730e6cSSean Christopherson static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t page, int level)
23467730e6cSSean Christopherson {
23567730e6cSSean Christopherson #ifdef DEBUG
23667730e6cSSean Christopherson 	static const char * const type[] = { "", "pud", "pmd", "pte" };
23767730e6cSSean Christopherson 	uint64_t pte, *ptep;
23867730e6cSSean Christopherson 
23967730e6cSSean Christopherson 	if (level == 4)
24067730e6cSSean Christopherson 		return;
24167730e6cSSean Christopherson 
24267730e6cSSean Christopherson 	for (pte = page; pte < page + ptrs_per_pte(vm) * 8; pte += 8) {
24367730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pte);
24467730e6cSSean Christopherson 		if (!*ptep)
24567730e6cSSean Christopherson 			continue;
24667730e6cSSean Christopherson 		fprintf(stream, "%*s%s: %lx: %lx at %p\n", indent, "", type[level], pte, *ptep, ptep);
24767730e6cSSean Christopherson 		pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level + 1);
24867730e6cSSean Christopherson 	}
24967730e6cSSean Christopherson #endif
25067730e6cSSean Christopherson }
25167730e6cSSean Christopherson 
virt_arch_dump(FILE * stream,struct kvm_vm * vm,uint8_t indent)25267730e6cSSean Christopherson void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
25367730e6cSSean Christopherson {
25467730e6cSSean Christopherson 	int level = 4 - (vm->pgtable_levels - 1);
25567730e6cSSean Christopherson 	uint64_t pgd, *ptep;
25667730e6cSSean Christopherson 
25767730e6cSSean Christopherson 	if (!vm->pgd_created)
25867730e6cSSean Christopherson 		return;
25967730e6cSSean Christopherson 
26067730e6cSSean Christopherson 	for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
26167730e6cSSean Christopherson 		ptep = addr_gpa2hva(vm, pgd);
26267730e6cSSean Christopherson 		if (!*ptep)
26367730e6cSSean Christopherson 			continue;
26467730e6cSSean Christopherson 		fprintf(stream, "%*spgd: %lx: %lx at %p\n", indent, "", pgd, *ptep, ptep);
26567730e6cSSean Christopherson 		pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level);
26667730e6cSSean Christopherson 	}
26767730e6cSSean Christopherson }
26867730e6cSSean Christopherson 
aarch64_vcpu_setup(struct kvm_vcpu * vcpu,struct kvm_vcpu_init * init)26967730e6cSSean Christopherson void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init)
27067730e6cSSean Christopherson {
27167730e6cSSean Christopherson 	struct kvm_vcpu_init default_init = { .target = -1, };
27267730e6cSSean Christopherson 	struct kvm_vm *vm = vcpu->vm;
27367730e6cSSean Christopherson 	uint64_t sctlr_el1, tcr_el1, ttbr0_el1;
27467730e6cSSean Christopherson 
27567730e6cSSean Christopherson 	if (!init)
27667730e6cSSean Christopherson 		init = &default_init;
27767730e6cSSean Christopherson 
27867730e6cSSean Christopherson 	if (init->target == -1) {
27967730e6cSSean Christopherson 		struct kvm_vcpu_init preferred;
28067730e6cSSean Christopherson 		vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &preferred);
28167730e6cSSean Christopherson 		init->target = preferred.target;
28267730e6cSSean Christopherson 	}
28367730e6cSSean Christopherson 
28467730e6cSSean Christopherson 	vcpu_ioctl(vcpu, KVM_ARM_VCPU_INIT, init);
28567730e6cSSean Christopherson 
28667730e6cSSean Christopherson 	/*
28767730e6cSSean Christopherson 	 * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15
28867730e6cSSean Christopherson 	 * registers, which the variable argument list macros do.
28967730e6cSSean Christopherson 	 */
29067730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20);
29167730e6cSSean Christopherson 
29267730e6cSSean Christopherson 	sctlr_el1 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1));
29367730e6cSSean Christopherson 	tcr_el1 = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1));
29467730e6cSSean Christopherson 
29567730e6cSSean Christopherson 	/* Configure base granule size */
29667730e6cSSean Christopherson 	switch (vm->mode) {
29767730e6cSSean Christopherson 	case VM_MODE_PXXV48_4K:
29867730e6cSSean Christopherson 		TEST_FAIL("AArch64 does not support 4K sized pages "
29967730e6cSSean Christopherson 			  "with ANY-bit physical address ranges");
30067730e6cSSean Christopherson 	case VM_MODE_P52V48_64K:
30167730e6cSSean Christopherson 	case VM_MODE_P48V48_64K:
30267730e6cSSean Christopherson 	case VM_MODE_P40V48_64K:
30367730e6cSSean Christopherson 	case VM_MODE_P36V48_64K:
304d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_TG0_64K;
30567730e6cSSean Christopherson 		break;
30667730e6cSSean Christopherson 	case VM_MODE_P52V48_16K:
30767730e6cSSean Christopherson 	case VM_MODE_P48V48_16K:
30867730e6cSSean Christopherson 	case VM_MODE_P40V48_16K:
30967730e6cSSean Christopherson 	case VM_MODE_P36V48_16K:
31067730e6cSSean Christopherson 	case VM_MODE_P36V47_16K:
311d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_TG0_16K;
31267730e6cSSean Christopherson 		break;
31367730e6cSSean Christopherson 	case VM_MODE_P52V48_4K:
31467730e6cSSean Christopherson 	case VM_MODE_P48V48_4K:
31567730e6cSSean Christopherson 	case VM_MODE_P40V48_4K:
31667730e6cSSean Christopherson 	case VM_MODE_P36V48_4K:
317d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_TG0_4K;
31867730e6cSSean Christopherson 		break;
31967730e6cSSean Christopherson 	default:
32067730e6cSSean Christopherson 		TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
32167730e6cSSean Christopherson 	}
32267730e6cSSean Christopherson 
32367730e6cSSean Christopherson 	ttbr0_el1 = vm->pgd & GENMASK(47, vm->page_shift);
32467730e6cSSean Christopherson 
32567730e6cSSean Christopherson 	/* Configure output size */
32667730e6cSSean Christopherson 	switch (vm->mode) {
32767730e6cSSean Christopherson 	case VM_MODE_P52V48_4K:
32867730e6cSSean Christopherson 	case VM_MODE_P52V48_16K:
32967730e6cSSean Christopherson 	case VM_MODE_P52V48_64K:
330d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_IPS_52_BITS;
33167730e6cSSean Christopherson 		ttbr0_el1 |= FIELD_GET(GENMASK(51, 48), vm->pgd) << 2;
33267730e6cSSean Christopherson 		break;
33367730e6cSSean Christopherson 	case VM_MODE_P48V48_4K:
33467730e6cSSean Christopherson 	case VM_MODE_P48V48_16K:
33567730e6cSSean Christopherson 	case VM_MODE_P48V48_64K:
336d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_IPS_48_BITS;
33767730e6cSSean Christopherson 		break;
33867730e6cSSean Christopherson 	case VM_MODE_P40V48_4K:
33967730e6cSSean Christopherson 	case VM_MODE_P40V48_16K:
34067730e6cSSean Christopherson 	case VM_MODE_P40V48_64K:
341d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_IPS_40_BITS;
34267730e6cSSean Christopherson 		break;
34367730e6cSSean Christopherson 	case VM_MODE_P36V48_4K:
34467730e6cSSean Christopherson 	case VM_MODE_P36V48_16K:
34567730e6cSSean Christopherson 	case VM_MODE_P36V48_64K:
34667730e6cSSean Christopherson 	case VM_MODE_P36V47_16K:
347d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_IPS_36_BITS;
34867730e6cSSean Christopherson 		break;
34967730e6cSSean Christopherson 	default:
35067730e6cSSean Christopherson 		TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
35167730e6cSSean Christopherson 	}
35267730e6cSSean Christopherson 
353d8d78398SRaghavendra Rao Ananta 	sctlr_el1 |= SCTLR_ELx_M | SCTLR_ELx_C | SCTLR_ELx_I;
354d8d78398SRaghavendra Rao Ananta 
355d8d78398SRaghavendra Rao Ananta 	tcr_el1 |= TCR_IRGN0_WBWA | TCR_ORGN0_WBWA | TCR_SH0_INNER;
356d8d78398SRaghavendra Rao Ananta 	tcr_el1 |= TCR_T0SZ(vm->va_bits);
35767730e6cSSean Christopherson 	if (use_lpa2_pte_format(vm))
358d8d78398SRaghavendra Rao Ananta 		tcr_el1 |= TCR_DS;
35967730e6cSSean Christopherson 
36067730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1);
36167730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1);
36267730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1);
36367730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), ttbr0_el1);
36467730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpu->id);
36567730e6cSSean Christopherson }
36667730e6cSSean Christopherson 
vcpu_arch_dump(FILE * stream,struct kvm_vcpu * vcpu,uint8_t indent)36767730e6cSSean Christopherson void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)
36867730e6cSSean Christopherson {
36967730e6cSSean Christopherson 	uint64_t pstate, pc;
37067730e6cSSean Christopherson 
37167730e6cSSean Christopherson 	pstate = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pstate));
37267730e6cSSean Christopherson 	pc = vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc));
37367730e6cSSean Christopherson 
37467730e6cSSean Christopherson 	fprintf(stream, "%*spstate: 0x%.16lx pc: 0x%.16lx\n",
37567730e6cSSean Christopherson 		indent, "", pstate, pc);
37667730e6cSSean Christopherson }
37767730e6cSSean Christopherson 
vcpu_arch_set_entry_point(struct kvm_vcpu * vcpu,void * guest_code)37867730e6cSSean Christopherson void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
37967730e6cSSean Christopherson {
38067730e6cSSean Christopherson 	vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
38167730e6cSSean Christopherson }
38267730e6cSSean Christopherson 
__aarch64_vcpu_add(struct kvm_vm * vm,uint32_t vcpu_id,struct kvm_vcpu_init * init)38367730e6cSSean Christopherson static struct kvm_vcpu *__aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
38467730e6cSSean Christopherson 					   struct kvm_vcpu_init *init)
38567730e6cSSean Christopherson {
38667730e6cSSean Christopherson 	size_t stack_size;
38767730e6cSSean Christopherson 	uint64_t stack_vaddr;
38867730e6cSSean Christopherson 	struct kvm_vcpu *vcpu = __vm_vcpu_add(vm, vcpu_id);
38967730e6cSSean Christopherson 
39067730e6cSSean Christopherson 	stack_size = vm->page_size == 4096 ? DEFAULT_STACK_PGS * vm->page_size :
39167730e6cSSean Christopherson 					     vm->page_size;
39267730e6cSSean Christopherson 	stack_vaddr = __vm_vaddr_alloc(vm, stack_size,
39367730e6cSSean Christopherson 				       DEFAULT_ARM64_GUEST_STACK_VADDR_MIN,
39467730e6cSSean Christopherson 				       MEM_REGION_DATA);
39567730e6cSSean Christopherson 
39667730e6cSSean Christopherson 	aarch64_vcpu_setup(vcpu, init);
39767730e6cSSean Christopherson 
39867730e6cSSean Christopherson 	vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size);
39967730e6cSSean Christopherson 	return vcpu;
40067730e6cSSean Christopherson }
40167730e6cSSean Christopherson 
aarch64_vcpu_add(struct kvm_vm * vm,uint32_t vcpu_id,struct kvm_vcpu_init * init,void * guest_code)40267730e6cSSean Christopherson struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id,
40367730e6cSSean Christopherson 				  struct kvm_vcpu_init *init, void *guest_code)
40467730e6cSSean Christopherson {
40567730e6cSSean Christopherson 	struct kvm_vcpu *vcpu = __aarch64_vcpu_add(vm, vcpu_id, init);
40667730e6cSSean Christopherson 
40767730e6cSSean Christopherson 	vcpu_arch_set_entry_point(vcpu, guest_code);
40867730e6cSSean Christopherson 
40967730e6cSSean Christopherson 	return vcpu;
41067730e6cSSean Christopherson }
41167730e6cSSean Christopherson 
vm_arch_vcpu_add(struct kvm_vm * vm,uint32_t vcpu_id)41267730e6cSSean Christopherson struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
41367730e6cSSean Christopherson {
41467730e6cSSean Christopherson 	return __aarch64_vcpu_add(vm, vcpu_id, NULL);
41567730e6cSSean Christopherson }
41667730e6cSSean Christopherson 
vcpu_args_set(struct kvm_vcpu * vcpu,unsigned int num,...)41767730e6cSSean Christopherson void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
41867730e6cSSean Christopherson {
41967730e6cSSean Christopherson 	va_list ap;
42067730e6cSSean Christopherson 	int i;
42167730e6cSSean Christopherson 
42267730e6cSSean Christopherson 	TEST_ASSERT(num >= 1 && num <= 8, "Unsupported number of args,\n"
42367730e6cSSean Christopherson 		    "  num: %u", num);
42467730e6cSSean Christopherson 
42567730e6cSSean Christopherson 	va_start(ap, num);
42667730e6cSSean Christopherson 
42767730e6cSSean Christopherson 	for (i = 0; i < num; i++) {
42867730e6cSSean Christopherson 		vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.regs[i]),
42967730e6cSSean Christopherson 			     va_arg(ap, uint64_t));
43067730e6cSSean Christopherson 	}
43167730e6cSSean Christopherson 
43267730e6cSSean Christopherson 	va_end(ap);
43367730e6cSSean Christopherson }
43467730e6cSSean Christopherson 
kvm_exit_unexpected_exception(int vector,uint64_t ec,bool valid_ec)43567730e6cSSean Christopherson void kvm_exit_unexpected_exception(int vector, uint64_t ec, bool valid_ec)
43667730e6cSSean Christopherson {
43767730e6cSSean Christopherson 	ucall(UCALL_UNHANDLED, 3, vector, ec, valid_ec);
43867730e6cSSean Christopherson 	while (1)
43967730e6cSSean Christopherson 		;
44067730e6cSSean Christopherson }
44167730e6cSSean Christopherson 
assert_on_unhandled_exception(struct kvm_vcpu * vcpu)44267730e6cSSean Christopherson void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
44367730e6cSSean Christopherson {
44467730e6cSSean Christopherson 	struct ucall uc;
44567730e6cSSean Christopherson 
44667730e6cSSean Christopherson 	if (get_ucall(vcpu, &uc) != UCALL_UNHANDLED)
44767730e6cSSean Christopherson 		return;
44867730e6cSSean Christopherson 
44967730e6cSSean Christopherson 	if (uc.args[2]) /* valid_ec */ {
45067730e6cSSean Christopherson 		assert(VECTOR_IS_SYNC(uc.args[0]));
45167730e6cSSean Christopherson 		TEST_FAIL("Unexpected exception (vector:0x%lx, ec:0x%lx)",
45267730e6cSSean Christopherson 			  uc.args[0], uc.args[1]);
45367730e6cSSean Christopherson 	} else {
45467730e6cSSean Christopherson 		assert(!VECTOR_IS_SYNC(uc.args[0]));
45567730e6cSSean Christopherson 		TEST_FAIL("Unexpected exception (vector:0x%lx)",
45667730e6cSSean Christopherson 			  uc.args[0]);
45767730e6cSSean Christopherson 	}
45867730e6cSSean Christopherson }
45967730e6cSSean Christopherson 
46067730e6cSSean Christopherson struct handlers {
46167730e6cSSean Christopherson 	handler_fn exception_handlers[VECTOR_NUM][ESR_ELx_EC_MAX + 1];
46267730e6cSSean Christopherson };
46367730e6cSSean Christopherson 
vcpu_init_descriptor_tables(struct kvm_vcpu * vcpu)46467730e6cSSean Christopherson void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu)
46567730e6cSSean Christopherson {
46667730e6cSSean Christopherson 	extern char vectors;
46767730e6cSSean Christopherson 
46867730e6cSSean Christopherson 	vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors);
46967730e6cSSean Christopherson }
47067730e6cSSean Christopherson 
route_exception(struct ex_regs * regs,int vector)47167730e6cSSean Christopherson void route_exception(struct ex_regs *regs, int vector)
47267730e6cSSean Christopherson {
47367730e6cSSean Christopherson 	struct handlers *handlers = (struct handlers *)exception_handlers;
47467730e6cSSean Christopherson 	bool valid_ec;
47567730e6cSSean Christopherson 	int ec = 0;
47667730e6cSSean Christopherson 
47767730e6cSSean Christopherson 	switch (vector) {
47867730e6cSSean Christopherson 	case VECTOR_SYNC_CURRENT:
47967730e6cSSean Christopherson 	case VECTOR_SYNC_LOWER_64:
48067730e6cSSean Christopherson 		ec = ESR_ELx_EC(read_sysreg(esr_el1));
48167730e6cSSean Christopherson 		valid_ec = true;
48267730e6cSSean Christopherson 		break;
48367730e6cSSean Christopherson 	case VECTOR_IRQ_CURRENT:
48467730e6cSSean Christopherson 	case VECTOR_IRQ_LOWER_64:
48567730e6cSSean Christopherson 	case VECTOR_FIQ_CURRENT:
48667730e6cSSean Christopherson 	case VECTOR_FIQ_LOWER_64:
48767730e6cSSean Christopherson 	case VECTOR_ERROR_CURRENT:
48867730e6cSSean Christopherson 	case VECTOR_ERROR_LOWER_64:
48967730e6cSSean Christopherson 		ec = 0;
49067730e6cSSean Christopherson 		valid_ec = false;
49167730e6cSSean Christopherson 		break;
49267730e6cSSean Christopherson 	default:
49367730e6cSSean Christopherson 		valid_ec = false;
49467730e6cSSean Christopherson 		goto unexpected_exception;
49567730e6cSSean Christopherson 	}
49667730e6cSSean Christopherson 
49767730e6cSSean Christopherson 	if (handlers && handlers->exception_handlers[vector][ec])
49867730e6cSSean Christopherson 		return handlers->exception_handlers[vector][ec](regs);
49967730e6cSSean Christopherson 
50067730e6cSSean Christopherson unexpected_exception:
50167730e6cSSean Christopherson 	kvm_exit_unexpected_exception(vector, ec, valid_ec);
50267730e6cSSean Christopherson }
50367730e6cSSean Christopherson 
vm_init_descriptor_tables(struct kvm_vm * vm)50467730e6cSSean Christopherson void vm_init_descriptor_tables(struct kvm_vm *vm)
50567730e6cSSean Christopherson {
50667730e6cSSean Christopherson 	vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers),
50767730e6cSSean Christopherson 					vm->page_size, MEM_REGION_DATA);
50867730e6cSSean Christopherson 
50967730e6cSSean Christopherson 	*(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers;
51067730e6cSSean Christopherson }
51167730e6cSSean Christopherson 
vm_install_sync_handler(struct kvm_vm * vm,int vector,int ec,void (* handler)(struct ex_regs *))51267730e6cSSean Christopherson void vm_install_sync_handler(struct kvm_vm *vm, int vector, int ec,
51367730e6cSSean Christopherson 			 void (*handler)(struct ex_regs *))
51467730e6cSSean Christopherson {
51567730e6cSSean Christopherson 	struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
51667730e6cSSean Christopherson 
51767730e6cSSean Christopherson 	assert(VECTOR_IS_SYNC(vector));
51867730e6cSSean Christopherson 	assert(vector < VECTOR_NUM);
51967730e6cSSean Christopherson 	assert(ec <= ESR_ELx_EC_MAX);
52067730e6cSSean Christopherson 	handlers->exception_handlers[vector][ec] = handler;
52167730e6cSSean Christopherson }
52267730e6cSSean Christopherson 
vm_install_exception_handler(struct kvm_vm * vm,int vector,void (* handler)(struct ex_regs *))52367730e6cSSean Christopherson void vm_install_exception_handler(struct kvm_vm *vm, int vector,
52467730e6cSSean Christopherson 			 void (*handler)(struct ex_regs *))
52567730e6cSSean Christopherson {
52667730e6cSSean Christopherson 	struct handlers *handlers = addr_gva2hva(vm, vm->handlers);
52767730e6cSSean Christopherson 
52867730e6cSSean Christopherson 	assert(!VECTOR_IS_SYNC(vector));
52967730e6cSSean Christopherson 	assert(vector < VECTOR_NUM);
53067730e6cSSean Christopherson 	handlers->exception_handlers[vector][0] = handler;
53167730e6cSSean Christopherson }
53267730e6cSSean Christopherson 
guest_get_vcpuid(void)53367730e6cSSean Christopherson uint32_t guest_get_vcpuid(void)
53467730e6cSSean Christopherson {
53567730e6cSSean Christopherson 	return read_sysreg(tpidr_el1);
53667730e6cSSean Christopherson }
53767730e6cSSean Christopherson 
max_ipa_for_page_size(uint32_t vm_ipa,uint32_t gran,uint32_t not_sup_val,uint32_t ipa52_min_val)53867730e6cSSean Christopherson static uint32_t max_ipa_for_page_size(uint32_t vm_ipa, uint32_t gran,
53967730e6cSSean Christopherson 				uint32_t not_sup_val, uint32_t ipa52_min_val)
54067730e6cSSean Christopherson {
54167730e6cSSean Christopherson 	if (gran == not_sup_val)
54267730e6cSSean Christopherson 		return 0;
54367730e6cSSean Christopherson 	else if (gran >= ipa52_min_val && vm_ipa >= 52)
54467730e6cSSean Christopherson 		return 52;
54567730e6cSSean Christopherson 	else
54667730e6cSSean Christopherson 		return min(vm_ipa, 48U);
54767730e6cSSean Christopherson }
54867730e6cSSean Christopherson 
aarch64_get_supported_page_sizes(uint32_t ipa,uint32_t * ipa4k,uint32_t * ipa16k,uint32_t * ipa64k)54967730e6cSSean Christopherson void aarch64_get_supported_page_sizes(uint32_t ipa, uint32_t *ipa4k,
55067730e6cSSean Christopherson 					uint32_t *ipa16k, uint32_t *ipa64k)
55167730e6cSSean Christopherson {
55267730e6cSSean Christopherson 	struct kvm_vcpu_init preferred_init;
55367730e6cSSean Christopherson 	int kvm_fd, vm_fd, vcpu_fd, err;
55467730e6cSSean Christopherson 	uint64_t val;
55567730e6cSSean Christopherson 	uint32_t gran;
55667730e6cSSean Christopherson 	struct kvm_one_reg reg = {
55767730e6cSSean Christopherson 		.id	= KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
55867730e6cSSean Christopherson 		.addr	= (uint64_t)&val,
55967730e6cSSean Christopherson 	};
56067730e6cSSean Christopherson 
56167730e6cSSean Christopherson 	kvm_fd = open_kvm_dev_path_or_exit();
56267730e6cSSean Christopherson 	vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, (void *)(unsigned long)ipa);
56367730e6cSSean Christopherson 	TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd));
56467730e6cSSean Christopherson 
56567730e6cSSean Christopherson 	vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
56667730e6cSSean Christopherson 	TEST_ASSERT(vcpu_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu_fd));
56767730e6cSSean Christopherson 
56867730e6cSSean Christopherson 	err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
56967730e6cSSean Christopherson 	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_PREFERRED_TARGET, err));
57067730e6cSSean Christopherson 	err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init);
57167730e6cSSean Christopherson 	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_VCPU_INIT, err));
57267730e6cSSean Christopherson 
57367730e6cSSean Christopherson 	err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
57467730e6cSSean Christopherson 	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd));
57567730e6cSSean Christopherson 
57667730e6cSSean Christopherson 	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN4), val);
57767730e6cSSean Christopherson 	*ipa4k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN4_NI,
57867730e6cSSean Christopherson 					ID_AA64MMFR0_EL1_TGRAN4_52_BIT);
57967730e6cSSean Christopherson 
58067730e6cSSean Christopherson 	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN64), val);
58167730e6cSSean Christopherson 	*ipa64k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN64_NI,
58267730e6cSSean Christopherson 					ID_AA64MMFR0_EL1_TGRAN64_IMP);
58367730e6cSSean Christopherson 
58467730e6cSSean Christopherson 	gran = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR0_EL1_TGRAN16), val);
58567730e6cSSean Christopherson 	*ipa16k = max_ipa_for_page_size(ipa, gran, ID_AA64MMFR0_EL1_TGRAN16_NI,
58667730e6cSSean Christopherson 					ID_AA64MMFR0_EL1_TGRAN16_52_BIT);
58767730e6cSSean Christopherson 
58867730e6cSSean Christopherson 	close(vcpu_fd);
58967730e6cSSean Christopherson 	close(vm_fd);
59067730e6cSSean Christopherson 	close(kvm_fd);
59167730e6cSSean Christopherson }
59267730e6cSSean Christopherson 
59367730e6cSSean Christopherson #define __smccc_call(insn, function_id, arg0, arg1, arg2, arg3, arg4, arg5,	\
59467730e6cSSean Christopherson 		     arg6, res)							\
59567730e6cSSean Christopherson 	asm volatile("mov   w0, %w[function_id]\n"				\
59667730e6cSSean Christopherson 		     "mov   x1, %[arg0]\n"					\
59767730e6cSSean Christopherson 		     "mov   x2, %[arg1]\n"					\
59867730e6cSSean Christopherson 		     "mov   x3, %[arg2]\n"					\
59967730e6cSSean Christopherson 		     "mov   x4, %[arg3]\n"					\
60067730e6cSSean Christopherson 		     "mov   x5, %[arg4]\n"					\
60167730e6cSSean Christopherson 		     "mov   x6, %[arg5]\n"					\
60267730e6cSSean Christopherson 		     "mov   x7, %[arg6]\n"					\
60367730e6cSSean Christopherson 		     #insn  "#0\n"						\
60467730e6cSSean Christopherson 		     "mov   %[res0], x0\n"					\
60567730e6cSSean Christopherson 		     "mov   %[res1], x1\n"					\
60667730e6cSSean Christopherson 		     "mov   %[res2], x2\n"					\
60767730e6cSSean Christopherson 		     "mov   %[res3], x3\n"					\
60867730e6cSSean Christopherson 		     : [res0] "=r"(res->a0), [res1] "=r"(res->a1),		\
60967730e6cSSean Christopherson 		       [res2] "=r"(res->a2), [res3] "=r"(res->a3)		\
61067730e6cSSean Christopherson 		     : [function_id] "r"(function_id), [arg0] "r"(arg0),	\
61167730e6cSSean Christopherson 		       [arg1] "r"(arg1), [arg2] "r"(arg2), [arg3] "r"(arg3),	\
61267730e6cSSean Christopherson 		       [arg4] "r"(arg4), [arg5] "r"(arg5), [arg6] "r"(arg6)	\
61367730e6cSSean Christopherson 		     : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7")
61467730e6cSSean Christopherson 
61567730e6cSSean Christopherson 
smccc_hvc(uint32_t function_id,uint64_t arg0,uint64_t arg1,uint64_t arg2,uint64_t arg3,uint64_t arg4,uint64_t arg5,uint64_t arg6,struct arm_smccc_res * res)61667730e6cSSean Christopherson void smccc_hvc(uint32_t function_id, uint64_t arg0, uint64_t arg1,
61767730e6cSSean Christopherson 	       uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5,
61867730e6cSSean Christopherson 	       uint64_t arg6, struct arm_smccc_res *res)
61967730e6cSSean Christopherson {
62067730e6cSSean Christopherson 	__smccc_call(hvc, function_id, arg0, arg1, arg2, arg3, arg4, arg5,
62167730e6cSSean Christopherson 		     arg6, res);
62267730e6cSSean Christopherson }
62367730e6cSSean Christopherson 
smccc_smc(uint32_t function_id,uint64_t arg0,uint64_t arg1,uint64_t arg2,uint64_t arg3,uint64_t arg4,uint64_t arg5,uint64_t arg6,struct arm_smccc_res * res)62467730e6cSSean Christopherson void smccc_smc(uint32_t function_id, uint64_t arg0, uint64_t arg1,
62567730e6cSSean Christopherson 	       uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5,
62667730e6cSSean Christopherson 	       uint64_t arg6, struct arm_smccc_res *res)
62767730e6cSSean Christopherson {
62867730e6cSSean Christopherson 	__smccc_call(smc, function_id, arg0, arg1, arg2, arg3, arg4, arg5,
62967730e6cSSean Christopherson 		     arg6, res);
63067730e6cSSean Christopherson }
63167730e6cSSean Christopherson 
kvm_selftest_arch_init(void)63267730e6cSSean Christopherson void kvm_selftest_arch_init(void)
63367730e6cSSean Christopherson {
63467730e6cSSean Christopherson 	/*
63567730e6cSSean Christopherson 	 * arm64 doesn't have a true default mode, so start by computing the
63667730e6cSSean Christopherson 	 * available IPA space and page sizes early.
63767730e6cSSean Christopherson 	 */
63867730e6cSSean Christopherson 	guest_modes_append_default();
63967730e6cSSean Christopherson }
64067730e6cSSean Christopherson 
vm_vaddr_populate_bitmap(struct kvm_vm * vm)64167730e6cSSean Christopherson void vm_vaddr_populate_bitmap(struct kvm_vm *vm)
64267730e6cSSean Christopherson {
64367730e6cSSean Christopherson 	/*
64467730e6cSSean Christopherson 	 * arm64 selftests use only TTBR0_EL1, meaning that the valid VA space
64567730e6cSSean Christopherson 	 * is [0, 2^(64 - TCR_EL1.T0SZ)).
64667730e6cSSean Christopherson 	 */
64767730e6cSSean Christopherson 	sparsebit_set_num(vm->vpages_valid, 0,
64867730e6cSSean Christopherson 			  (1ULL << vm->va_bits) >> vm->page_shift);
64967730e6cSSean Christopherson }
65067730e6cSSean Christopherson 
65167730e6cSSean Christopherson /* Helper to call wfi instruction. */
wfi(void)65267730e6cSSean Christopherson void wfi(void)
65367730e6cSSean Christopherson {
65467730e6cSSean Christopherson 	asm volatile("wfi");
65567730e6cSSean Christopherson }
656