Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kvm: selftests: add vcpu support for aarch64

This code adds VM and VCPU setup code for the VM_MODE_FLAT48PG mode.
The VM_MODE_FLAT48PG isn't yet fully supportable, as it defines the
guest physical address limit as 52-bits, and KVM currently only
supports guests with up to 40-bit physical addresses (see
KVM_PHYS_SHIFT). VM_MODE_FLAT48PG will work fine, though, as long as
no >= 40-bit physical addresses are used.

Signed-off-by: Andrew Jones <drjones@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Andrew Jones and committed by
Paolo Bonzini
0bec140f 7a6629ef

+138
+55
tools/testing/selftests/kvm/include/aarch64/processor.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * AArch64 processor specific defines 4 + * 5 + * Copyright (C) 2018, Red Hat, Inc. 6 + */ 7 + #ifndef SELFTEST_KVM_PROCESSOR_H 8 + #define SELFTEST_KVM_PROCESSOR_H 9 + 10 + #include "kvm_util.h" 11 + 12 + 13 + #define ARM64_CORE_REG(x) (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | \ 14 + KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(x)) 15 + 16 + #define CPACR_EL1 3, 0, 1, 0, 2 17 + #define TCR_EL1 3, 0, 2, 0, 2 18 + #define MAIR_EL1 3, 0, 10, 2, 0 19 + #define TTBR0_EL1 3, 0, 2, 0, 0 20 + #define SCTLR_EL1 3, 0, 1, 0, 0 21 + 22 + /* 23 + * Default MAIR 24 + * index attribute 25 + * DEVICE_nGnRnE 0 0000:0000 26 + * DEVICE_nGnRE 1 0000:0100 27 + * DEVICE_GRE 2 0000:1100 28 + * NORMAL_NC 3 0100:0100 29 + * NORMAL 4 1111:1111 30 + * NORMAL_WT 5 1011:1011 31 + */ 32 + #define DEFAULT_MAIR_EL1 ((0x00ul << (0 * 8)) | \ 33 + (0x04ul << (1 * 8)) | \ 34 + (0x0cul << (2 * 8)) | \ 35 + (0x44ul << (3 * 8)) | \ 36 + (0xfful << (4 * 8)) | \ 37 + (0xbbul << (5 * 8))) 38 + 39 + static inline void get_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t *addr) 40 + { 41 + struct kvm_one_reg reg; 42 + reg.id = id; 43 + reg.addr = (uint64_t)addr; 44 + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, &reg); 45 + } 46 + 47 + static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t val) 48 + { 49 + struct kvm_one_reg reg; 50 + reg.id = id; 51 + reg.addr = (uint64_t)&val; 52 + vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, &reg); 53 + } 54 + 55 + #endif /* SELFTEST_KVM_PROCESSOR_H */
+83
tools/testing/selftests/kvm/lib/aarch64/processor.c
··· 5 5 * Copyright (C) 2018, Red Hat, Inc. 6 6 */ 7 7 8 + #define _GNU_SOURCE /* for program_invocation_name */ 9 + 8 10 #include "kvm_util.h" 9 11 #include "../kvm_util_internal.h" 12 + #include "processor.h" 10 13 11 14 #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 15 + #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 12 16 13 17 static uint64_t page_align(struct kvm_vm *vm, uint64_t v) 14 18 { ··· 217 213 printf("%*spgd: %lx: %lx at %p\n", indent, "", pgd, *ptep, ptep); 218 214 pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level); 219 215 } 216 + } 217 + 218 + struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, 219 + void *guest_code) 220 + { 221 + uint64_t ptrs_per_4k_pte = 512; 222 + uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2; 223 + struct kvm_vm *vm; 224 + 225 + vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); 226 + 227 + kvm_vm_elf_load(vm, program_invocation_name, 0, 0); 228 + vm_vcpu_add_default(vm, vcpuid, guest_code); 229 + 230 + return vm; 231 + } 232 + 233 + void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) 234 + { 235 + size_t stack_size = vm->page_size == 4096 ? 236 + DEFAULT_STACK_PGS * vm->page_size : 237 + vm->page_size; 238 + uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size, 239 + DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0); 240 + 241 + vm_vcpu_add(vm, vcpuid, 0, 0); 242 + 243 + set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); 244 + set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); 245 + } 246 + 247 + void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot) 248 + { 249 + struct kvm_vcpu_init init; 250 + uint64_t sctlr_el1, tcr_el1; 251 + 252 + memset(&init, 0, sizeof(init)); 253 + init.target = KVM_ARM_TARGET_GENERIC_V8; 254 + vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, &init); 255 + 256 + /* 257 + * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 258 + * registers, which the variable argument list macros do. 259 + */ 260 + set_reg(vm, vcpuid, ARM64_SYS_REG(CPACR_EL1), 3 << 20); 261 + 262 + get_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), &sctlr_el1); 263 + get_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), &tcr_el1); 264 + 265 + switch (vm->mode) { 266 + case VM_MODE_FLAT48PG: 267 + tcr_el1 |= 0ul << 14; /* TG0 = 4KB */ 268 + tcr_el1 |= 6ul << 32; /* IPS = 52 bits */ 269 + break; 270 + default: 271 + TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); 272 + } 273 + 274 + sctlr_el1 |= (1 << 0) | (1 << 2) | (1 << 12) /* M | C | I */; 275 + /* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */; 276 + tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); 277 + tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; 278 + 279 + set_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), sctlr_el1); 280 + set_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), tcr_el1); 281 + set_reg(vm, vcpuid, ARM64_SYS_REG(MAIR_EL1), DEFAULT_MAIR_EL1); 282 + set_reg(vm, vcpuid, ARM64_SYS_REG(TTBR0_EL1), vm->pgd); 283 + } 284 + 285 + void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) 286 + { 287 + uint64_t pstate, pc; 288 + 289 + get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); 290 + get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); 291 + 292 + fprintf(stream, "%*spstate: 0x%.16llx pc: 0x%.16llx\n", 293 + indent, "", pstate, pc); 294 + 220 295 }