pkvm.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 - Google LLC
  4. * Author: Quentin Perret <qperret@google.com>
  5. */
  6. #include <linux/init.h>
  7. #include <linux/kmemleak.h>
  8. #include <linux/kvm_host.h>
  9. #include <linux/memblock.h>
  10. #include <linux/mutex.h>
  11. #include <linux/sort.h>
  12. #include <asm/kvm_pkvm.h>
  13. #include "hyp_constants.h"
  14. DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
  15. static struct memblock_region *hyp_memory = kvm_nvhe_sym(hyp_memory);
  16. static unsigned int *hyp_memblock_nr_ptr = &kvm_nvhe_sym(hyp_memblock_nr);
  17. phys_addr_t hyp_mem_base;
  18. phys_addr_t hyp_mem_size;
  19. static int cmp_hyp_memblock(const void *p1, const void *p2)
  20. {
  21. const struct memblock_region *r1 = p1;
  22. const struct memblock_region *r2 = p2;
  23. return r1->base < r2->base ? -1 : (r1->base > r2->base);
  24. }
  25. static void __init sort_memblock_regions(void)
  26. {
  27. sort(hyp_memory,
  28. *hyp_memblock_nr_ptr,
  29. sizeof(struct memblock_region),
  30. cmp_hyp_memblock,
  31. NULL);
  32. }
  33. static int __init register_memblock_regions(void)
  34. {
  35. struct memblock_region *reg;
  36. for_each_mem_region(reg) {
  37. if (*hyp_memblock_nr_ptr >= HYP_MEMBLOCK_REGIONS)
  38. return -ENOMEM;
  39. hyp_memory[*hyp_memblock_nr_ptr] = *reg;
  40. (*hyp_memblock_nr_ptr)++;
  41. }
  42. sort_memblock_regions();
  43. return 0;
  44. }
  45. void __init kvm_hyp_reserve(void)
  46. {
  47. u64 hyp_mem_pages = 0;
  48. int ret;
  49. if (!is_hyp_mode_available() || is_kernel_in_hyp_mode())
  50. return;
  51. if (kvm_get_mode() != KVM_MODE_PROTECTED)
  52. return;
  53. ret = register_memblock_regions();
  54. if (ret) {
  55. *hyp_memblock_nr_ptr = 0;
  56. kvm_err("Failed to register hyp memblocks: %d\n", ret);
  57. return;
  58. }
  59. hyp_mem_pages += hyp_s1_pgtable_pages();
  60. hyp_mem_pages += host_s2_pgtable_pages();
  61. hyp_mem_pages += hyp_vm_table_pages();
  62. hyp_mem_pages += hyp_vmemmap_pages(STRUCT_HYP_PAGE_SIZE);
  63. hyp_mem_pages += hyp_ffa_proxy_pages();
  64. /*
  65. * Try to allocate a PMD-aligned region to reduce TLB pressure once
  66. * this is unmapped from the host stage-2, and fallback to PAGE_SIZE.
  67. */
  68. hyp_mem_size = hyp_mem_pages << PAGE_SHIFT;
  69. hyp_mem_base = memblock_phys_alloc(ALIGN(hyp_mem_size, PMD_SIZE),
  70. PMD_SIZE);
  71. if (!hyp_mem_base)
  72. hyp_mem_base = memblock_phys_alloc(hyp_mem_size, PAGE_SIZE);
  73. else
  74. hyp_mem_size = ALIGN(hyp_mem_size, PMD_SIZE);
  75. if (!hyp_mem_base) {
  76. kvm_err("Failed to reserve hyp memory\n");
  77. return;
  78. }
  79. kvm_info("Reserved %lld MiB at 0x%llx\n", hyp_mem_size >> 20,
  80. hyp_mem_base);
  81. }
  82. static void __pkvm_destroy_hyp_vm(struct kvm *host_kvm)
  83. {
  84. if (host_kvm->arch.pkvm.handle) {
  85. WARN_ON(kvm_call_hyp_nvhe(__pkvm_teardown_vm,
  86. host_kvm->arch.pkvm.handle));
  87. }
  88. host_kvm->arch.pkvm.handle = 0;
  89. free_hyp_memcache(&host_kvm->arch.pkvm.teardown_mc);
  90. }
  91. /*
  92. * Allocates and donates memory for hypervisor VM structs at EL2.
  93. *
  94. * Allocates space for the VM state, which includes the hyp vm as well as
  95. * the hyp vcpus.
  96. *
  97. * Stores an opaque handler in the kvm struct for future reference.
  98. *
  99. * Return 0 on success, negative error code on failure.
  100. */
  101. static int __pkvm_create_hyp_vm(struct kvm *host_kvm)
  102. {
  103. size_t pgd_sz, hyp_vm_sz, hyp_vcpu_sz;
  104. struct kvm_vcpu *host_vcpu;
  105. pkvm_handle_t handle;
  106. void *pgd, *hyp_vm;
  107. unsigned long idx;
  108. int ret;
  109. if (host_kvm->created_vcpus < 1)
  110. return -EINVAL;
  111. pgd_sz = kvm_pgtable_stage2_pgd_size(host_kvm->arch.mmu.vtcr);
  112. /*
  113. * The PGD pages will be reclaimed using a hyp_memcache which implies
  114. * page granularity. So, use alloc_pages_exact() to get individual
  115. * refcounts.
  116. */
  117. pgd = alloc_pages_exact(pgd_sz, GFP_KERNEL_ACCOUNT);
  118. if (!pgd)
  119. return -ENOMEM;
  120. /* Allocate memory to donate to hyp for vm and vcpu pointers. */
  121. hyp_vm_sz = PAGE_ALIGN(size_add(PKVM_HYP_VM_SIZE,
  122. size_mul(sizeof(void *),
  123. host_kvm->created_vcpus)));
  124. hyp_vm = alloc_pages_exact(hyp_vm_sz, GFP_KERNEL_ACCOUNT);
  125. if (!hyp_vm) {
  126. ret = -ENOMEM;
  127. goto free_pgd;
  128. }
  129. /* Donate the VM memory to hyp and let hyp initialize it. */
  130. ret = kvm_call_hyp_nvhe(__pkvm_init_vm, host_kvm, hyp_vm, pgd);
  131. if (ret < 0)
  132. goto free_vm;
  133. handle = ret;
  134. host_kvm->arch.pkvm.handle = handle;
  135. /* Donate memory for the vcpus at hyp and initialize it. */
  136. hyp_vcpu_sz = PAGE_ALIGN(PKVM_HYP_VCPU_SIZE);
  137. kvm_for_each_vcpu(idx, host_vcpu, host_kvm) {
  138. void *hyp_vcpu;
  139. /* Indexing of the vcpus to be sequential starting at 0. */
  140. if (WARN_ON(host_vcpu->vcpu_idx != idx)) {
  141. ret = -EINVAL;
  142. goto destroy_vm;
  143. }
  144. hyp_vcpu = alloc_pages_exact(hyp_vcpu_sz, GFP_KERNEL_ACCOUNT);
  145. if (!hyp_vcpu) {
  146. ret = -ENOMEM;
  147. goto destroy_vm;
  148. }
  149. ret = kvm_call_hyp_nvhe(__pkvm_init_vcpu, handle, host_vcpu,
  150. hyp_vcpu);
  151. if (ret) {
  152. free_pages_exact(hyp_vcpu, hyp_vcpu_sz);
  153. goto destroy_vm;
  154. }
  155. }
  156. return 0;
  157. destroy_vm:
  158. __pkvm_destroy_hyp_vm(host_kvm);
  159. return ret;
  160. free_vm:
  161. free_pages_exact(hyp_vm, hyp_vm_sz);
  162. free_pgd:
  163. free_pages_exact(pgd, pgd_sz);
  164. return ret;
  165. }
  166. int pkvm_create_hyp_vm(struct kvm *host_kvm)
  167. {
  168. int ret = 0;
  169. mutex_lock(&host_kvm->arch.config_lock);
  170. if (!host_kvm->arch.pkvm.handle)
  171. ret = __pkvm_create_hyp_vm(host_kvm);
  172. mutex_unlock(&host_kvm->arch.config_lock);
  173. return ret;
  174. }
  175. void pkvm_destroy_hyp_vm(struct kvm *host_kvm)
  176. {
  177. mutex_lock(&host_kvm->arch.config_lock);
  178. __pkvm_destroy_hyp_vm(host_kvm);
  179. mutex_unlock(&host_kvm->arch.config_lock);
  180. }
  181. int pkvm_init_host_vm(struct kvm *host_kvm)
  182. {
  183. return 0;
  184. }
  185. static void __init _kvm_host_prot_finalize(void *arg)
  186. {
  187. int *err = arg;
  188. if (WARN_ON(kvm_call_hyp_nvhe(__pkvm_prot_finalize)))
  189. WRITE_ONCE(*err, -EINVAL);
  190. }
  191. static int __init pkvm_drop_host_privileges(void)
  192. {
  193. int ret = 0;
  194. /*
  195. * Flip the static key upfront as that may no longer be possible
  196. * once the host stage 2 is installed.
  197. */
  198. static_branch_enable(&kvm_protected_mode_initialized);
  199. on_each_cpu(_kvm_host_prot_finalize, &ret, 1);
  200. return ret;
  201. }
  202. static int __init finalize_pkvm(void)
  203. {
  204. int ret;
  205. if (!is_protected_kvm_enabled() || !is_kvm_arm_initialised())
  206. return 0;
  207. /*
  208. * Exclude HYP sections from kmemleak so that they don't get peeked
  209. * at, which would end badly once inaccessible.
  210. */
  211. kmemleak_free_part(__hyp_bss_start, __hyp_bss_end - __hyp_bss_start);
  212. kmemleak_free_part(__hyp_rodata_start, __hyp_rodata_end - __hyp_rodata_start);
  213. kmemleak_free_part_phys(hyp_mem_base, hyp_mem_size);
  214. ret = pkvm_drop_host_privileges();
  215. if (ret)
  216. pr_err("Failed to finalize Hyp protection: %d\n", ret);
  217. return ret;
  218. }
  219. device_initcall_sync(finalize_pkvm);