Home | History | Annotate | Download | only in aarch64
      1 // SPDX-License-Identifier: GPL-2.0
      2 /*
      3  * AArch64 code
      4  *
      5  * Copyright (C) 2018, Red Hat, Inc.
      6  */
      7 
      8 #define _GNU_SOURCE /* for program_invocation_name */
      9 
     10 #include "kvm_util.h"
     11 #include "../kvm_util_internal.h"
     12 #include "processor.h"
     13 
     14 #define KVM_GUEST_PAGE_TABLE_MIN_PADDR		0x180000
     15 #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN	0xac0000
     16 
     17 static uint64_t page_align(struct kvm_vm *vm, uint64_t v)
     18 {
     19 	return (v + vm->page_size) & ~(vm->page_size - 1);
     20 }
     21 
     22 static uint64_t pgd_index(struct kvm_vm *vm, vm_vaddr_t gva)
     23 {
     24 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
     25 	uint64_t mask = (1UL << (vm->va_bits - shift)) - 1;
     26 
     27 	return (gva >> shift) & mask;
     28 }
     29 
     30 static uint64_t pud_index(struct kvm_vm *vm, vm_vaddr_t gva)
     31 {
     32 	unsigned int shift = 2 * (vm->page_shift - 3) + vm->page_shift;
     33 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
     34 
     35 	TEST_ASSERT(vm->pgtable_levels == 4,
     36 		"Mode %d does not have 4 page table levels", vm->mode);
     37 
     38 	return (gva >> shift) & mask;
     39 }
     40 
     41 static uint64_t pmd_index(struct kvm_vm *vm, vm_vaddr_t gva)
     42 {
     43 	unsigned int shift = (vm->page_shift - 3) + vm->page_shift;
     44 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
     45 
     46 	TEST_ASSERT(vm->pgtable_levels >= 3,
     47 		"Mode %d does not have >= 3 page table levels", vm->mode);
     48 
     49 	return (gva >> shift) & mask;
     50 }
     51 
     52 static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva)
     53 {
     54 	uint64_t mask = (1UL << (vm->page_shift - 3)) - 1;
     55 	return (gva >> vm->page_shift) & mask;
     56 }
     57 
     58 static uint64_t pte_addr(struct kvm_vm *vm, uint64_t entry)
     59 {
     60 	uint64_t mask = ((1UL << (vm->va_bits - vm->page_shift)) - 1) << vm->page_shift;
     61 	return entry & mask;
     62 }
     63 
     64 static uint64_t ptrs_per_pgd(struct kvm_vm *vm)
     65 {
     66 	unsigned int shift = (vm->pgtable_levels - 1) * (vm->page_shift - 3) + vm->page_shift;
     67 	return 1 << (vm->va_bits - shift);
     68 }
     69 
     70 static uint64_t ptrs_per_pte(struct kvm_vm *vm)
     71 {
     72 	return 1 << (vm->page_shift - 3);
     73 }
     74 
     75 void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot)
     76 {
     77 	int rc;
     78 
     79 	if (!vm->pgd_created) {
     80 		vm_paddr_t paddr = vm_phy_pages_alloc(vm,
     81 			page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_size,
     82 			KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
     83 		vm->pgd = paddr;
     84 		vm->pgd_created = true;
     85 	}
     86 }
     87 
     88 void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
     89 		  uint32_t pgd_memslot, uint64_t flags)
     90 {
     91 	uint8_t attr_idx = flags & 7;
     92 	uint64_t *ptep;
     93 
     94 	TEST_ASSERT((vaddr % vm->page_size) == 0,
     95 		"Virtual address not on page boundary,\n"
     96 		"  vaddr: 0x%lx vm->page_size: 0x%x", vaddr, vm->page_size);
     97 	TEST_ASSERT(sparsebit_is_set(vm->vpages_valid,
     98 		(vaddr >> vm->page_shift)),
     99 		"Invalid virtual address, vaddr: 0x%lx", vaddr);
    100 	TEST_ASSERT((paddr % vm->page_size) == 0,
    101 		"Physical address not on page boundary,\n"
    102 		"  paddr: 0x%lx vm->page_size: 0x%x", paddr, vm->page_size);
    103 	TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn,
    104 		"Physical address beyond beyond maximum supported,\n"
    105 		"  paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x",
    106 		paddr, vm->max_gfn, vm->page_size);
    107 
    108 	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8;
    109 	if (!*ptep) {
    110 		*ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
    111 		*ptep |= 3;
    112 	}
    113 
    114 	switch (vm->pgtable_levels) {
    115 	case 4:
    116 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8;
    117 		if (!*ptep) {
    118 			*ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
    119 			*ptep |= 3;
    120 		}
    121 		/* fall through */
    122 	case 3:
    123 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8;
    124 		if (!*ptep) {
    125 			*ptep = vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot);
    126 			*ptep |= 3;
    127 		}
    128 		/* fall through */
    129 	case 2:
    130 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8;
    131 		break;
    132 	default:
    133 		TEST_ASSERT(false, "Page table levels must be 2, 3, or 4");
    134 	}
    135 
    136 	*ptep = paddr | 3;
    137 	*ptep |= (attr_idx << 2) | (1 << 10) /* Access Flag */;
    138 }
    139 
    140 void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr,
    141 		 uint32_t pgd_memslot)
    142 {
    143 	uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */
    144 
    145 	_virt_pg_map(vm, vaddr, paddr, pgd_memslot, attr_idx);
    146 }
    147 
    148 vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
    149 {
    150 	uint64_t *ptep;
    151 
    152 	if (!vm->pgd_created)
    153 		goto unmapped_gva;
    154 
    155 	ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, gva) * 8;
    156 	if (!ptep)
    157 		goto unmapped_gva;
    158 
    159 	switch (vm->pgtable_levels) {
    160 	case 4:
    161 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, gva) * 8;
    162 		if (!ptep)
    163 			goto unmapped_gva;
    164 		/* fall through */
    165 	case 3:
    166 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, gva) * 8;
    167 		if (!ptep)
    168 			goto unmapped_gva;
    169 		/* fall through */
    170 	case 2:
    171 		ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8;
    172 		if (!ptep)
    173 			goto unmapped_gva;
    174 		break;
    175 	default:
    176 		TEST_ASSERT(false, "Page table levels must be 2, 3, or 4");
    177 	}
    178 
    179 	return pte_addr(vm, *ptep) + (gva & (vm->page_size - 1));
    180 
    181 unmapped_gva:
    182 	TEST_ASSERT(false, "No mapping for vm virtual address, "
    183 		    "gva: 0x%lx", gva);
    184 }
    185 
    186 static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t page, int level)
    187 {
    188 #ifdef DEBUG_VM
    189 	static const char * const type[] = { "", "pud", "pmd", "pte" };
    190 	uint64_t pte, *ptep;
    191 
    192 	if (level == 4)
    193 		return;
    194 
    195 	for (pte = page; pte < page + ptrs_per_pte(vm) * 8; pte += 8) {
    196 		ptep = addr_gpa2hva(vm, pte);
    197 		if (!*ptep)
    198 			continue;
    199 		printf("%*s%s: %lx: %lx at %p\n", indent, "", type[level], pte, *ptep, ptep);
    200 		pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level + 1);
    201 	}
    202 #endif
    203 }
    204 
    205 void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent)
    206 {
    207 	int level = 4 - (vm->pgtable_levels - 1);
    208 	uint64_t pgd, *ptep;
    209 
    210 	if (!vm->pgd_created)
    211 		return;
    212 
    213 	for (pgd = vm->pgd; pgd < vm->pgd + ptrs_per_pgd(vm) * 8; pgd += 8) {
    214 		ptep = addr_gpa2hva(vm, pgd);
    215 		if (!*ptep)
    216 			continue;
    217 		printf("%*spgd: %lx: %lx at %p\n", indent, "", pgd, *ptep, ptep);
    218 		pte_dump(stream, vm, indent + 1, pte_addr(vm, *ptep), level);
    219 	}
    220 }
    221 
    222 struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages,
    223 				 void *guest_code)
    224 {
    225 	uint64_t ptrs_per_4k_pte = 512;
    226 	uint64_t extra_pg_pages = (extra_mem_pages / ptrs_per_4k_pte) * 2;
    227 	struct kvm_vm *vm;
    228 
    229 	vm = vm_create(VM_MODE_P52V48_4K, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR);
    230 
    231 	kvm_vm_elf_load(vm, program_invocation_name, 0, 0);
    232 	vm_vcpu_add_default(vm, vcpuid, guest_code);
    233 
    234 	return vm;
    235 }
    236 
    237 void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
    238 {
    239 	size_t stack_size = vm->page_size == 4096 ?
    240 					DEFAULT_STACK_PGS * vm->page_size :
    241 					vm->page_size;
    242 	uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size,
    243 					DEFAULT_ARM64_GUEST_STACK_VADDR_MIN, 0, 0);
    244 
    245 	vm_vcpu_add(vm, vcpuid, 0, 0);
    246 
    247 	set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size);
    248 	set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code);
    249 }
    250 
    251 void vcpu_setup(struct kvm_vm *vm, int vcpuid, int pgd_memslot, int gdt_memslot)
    252 {
    253 	struct kvm_vcpu_init init;
    254 	uint64_t sctlr_el1, tcr_el1;
    255 
    256 	memset(&init, 0, sizeof(init));
    257 	init.target = KVM_ARM_TARGET_GENERIC_V8;
    258 	vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, &init);
    259 
    260 	/*
    261 	 * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15
    262 	 * registers, which the variable argument list macros do.
    263 	 */
    264 	set_reg(vm, vcpuid, ARM64_SYS_REG(CPACR_EL1), 3 << 20);
    265 
    266 	get_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), &sctlr_el1);
    267 	get_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), &tcr_el1);
    268 
    269 	switch (vm->mode) {
    270 	case VM_MODE_P52V48_4K:
    271 		tcr_el1 |= 0ul << 14; /* TG0 = 4KB */
    272 		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
    273 		break;
    274 	case VM_MODE_P52V48_64K:
    275 		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
    276 		tcr_el1 |= 6ul << 32; /* IPS = 52 bits */
    277 		break;
    278 	case VM_MODE_P40V48_4K:
    279 		tcr_el1 |= 0ul << 14; /* TG0 = 4KB */
    280 		tcr_el1 |= 2ul << 32; /* IPS = 40 bits */
    281 		break;
    282 	case VM_MODE_P40V48_64K:
    283 		tcr_el1 |= 1ul << 14; /* TG0 = 64KB */
    284 		tcr_el1 |= 2ul << 32; /* IPS = 40 bits */
    285 		break;
    286 	default:
    287 		TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode);
    288 	}
    289 
    290 	sctlr_el1 |= (1 << 0) | (1 << 2) | (1 << 12) /* M | C | I */;
    291 	/* TCR_EL1 |= IRGN0:WBWA | ORGN0:WBWA | SH0:Inner-Shareable */;
    292 	tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12);
    293 	tcr_el1 |= (64 - vm->va_bits) /* T0SZ */;
    294 
    295 	set_reg(vm, vcpuid, ARM64_SYS_REG(SCTLR_EL1), sctlr_el1);
    296 	set_reg(vm, vcpuid, ARM64_SYS_REG(TCR_EL1), tcr_el1);
    297 	set_reg(vm, vcpuid, ARM64_SYS_REG(MAIR_EL1), DEFAULT_MAIR_EL1);
    298 	set_reg(vm, vcpuid, ARM64_SYS_REG(TTBR0_EL1), vm->pgd);
    299 }
    300 
    301 void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent)
    302 {
    303 	uint64_t pstate, pc;
    304 
    305 	get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate);
    306 	get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc);
    307 
    308         fprintf(stream, "%*spstate: 0x%.16llx pc: 0x%.16llx\n",
    309                 indent, "", pstate, pc);
    310 
    311 }
    312