mem_relinquish.c 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2022 Google LLC
  4. * Author: Keir Fraser <[email protected]>
  5. */
  6. #include <linux/arm-smccc.h>
  7. #include <linux/mem_relinquish.h>
  8. #include <linux/memory.h>
  9. #include <linux/mm.h>
  10. #include <linux/types.h>
  11. #include <asm/hypervisor.h>
  12. static unsigned long memshare_granule_sz;
  13. static void kvm_page_relinquish(struct page *page)
  14. {
  15. phys_addr_t phys, end;
  16. u32 func_id = ARM_SMCCC_VENDOR_HYP_KVM_MEM_RELINQUISH_FUNC_ID;
  17. phys = page_to_phys(page);
  18. end = phys + PAGE_SIZE;
  19. while (phys < end) {
  20. struct arm_smccc_res res;
  21. arm_smccc_1_1_invoke(func_id, phys, 0, 0, &res);
  22. BUG_ON(res.a0 != SMCCC_RET_SUCCESS);
  23. phys += memshare_granule_sz;
  24. }
  25. }
  26. void kvm_init_memrelinquish_services(void)
  27. {
  28. int i;
  29. struct arm_smccc_res res;
  30. const u32 funcs[] = {
  31. ARM_SMCCC_KVM_FUNC_HYP_MEMINFO,
  32. ARM_SMCCC_KVM_FUNC_MEM_RELINQUISH,
  33. };
  34. for (i = 0; i < ARRAY_SIZE(funcs); ++i) {
  35. if (!kvm_arm_hyp_service_available(funcs[i]))
  36. return;
  37. }
  38. arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_HYP_MEMINFO_FUNC_ID,
  39. 0, 0, 0, &res);
  40. if (res.a0 > PAGE_SIZE) /* Includes error codes */
  41. return;
  42. memshare_granule_sz = res.a0;
  43. if (memshare_granule_sz)
  44. hyp_ops.page_relinquish = kvm_page_relinquish;
  45. }
  46. bool kvm_has_memrelinquish_services(void)
  47. {
  48. return !!memshare_granule_sz;
  49. }
  50. EXPORT_SYMBOL_GPL(kvm_has_memrelinquish_services);
  51. void page_relinquish(struct page *page)
  52. {
  53. if (hyp_ops.page_relinquish)
  54. hyp_ops.page_relinquish(page);
  55. }
  56. EXPORT_SYMBOL_GPL(page_relinquish);
  57. void post_page_relinquish_tlb_inv(void)
  58. {
  59. if (hyp_ops.post_page_relinquish_tlb_inv)
  60. hyp_ops.post_page_relinquish_tlb_inv();
  61. }
  62. EXPORT_SYMBOL_GPL(post_page_relinquish_tlb_inv);