blob: b6c758eddc25f7cd94c81cdb68d84697a6e1c5e1 [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. */
#include <linux/gunyah.h>
#include <linux/init.h>
#include <linux/virtio_balloon.h>
#include <asm/hypervisor.h>
#define ADDRSPACE_INFO_AREA_ROOTVM_ADDRSPACE_CAP ((uint16_t)0)
struct addrspace_info_area_rootvm_addrspace_cap {
u64 addrspace_cap;
u32 rights;
u32 res0;
};
static u64 our_addrspace_capid;
#ifdef CONFIG_VIRTIO_BALLOON_HYP_OPS
static void gunyah_page_relinquish(struct page *page, unsigned int nr)
{
/* Release page to Host, so unlock and sanitize */
u64 flags = BIT_ULL(GUNYAH_ADDRSPC_MODIFY_FLAG_UNLOCK_BIT) |
BIT_ULL(GUNYAH_ADDRSPC_MODIFY_FLAG_SANITIZE_BIT);
phys_addr_t phys, end;
int ret = 0;
phys = page_to_phys(page);
end = phys + PAGE_SIZE * nr;
while (phys < end) {
ret = gunyah_hypercall_addrspc_modify_pages(our_addrspace_capid,
phys, PAGE_SIZE, flags);
if (ret)
pr_err_ratelimited("Failed to relinquish page: %016llx %d\n", phys, ret);
phys += PAGE_SIZE;
}
}
static void gunyah_post_page_relinquish_tlb_inv(void)
{
/* Release page to Host, so unlock and sanitize */
int ret = 0;
ret = gunyah_hypercall_addrspc_modify_pages(our_addrspace_capid, 0, 0, 0);
if (ret)
pr_err_ratelimited("Failed to flush tlb: %d\n", ret);
}
static struct virtio_balloon_hyp_ops gunyah_virtio_balloon_hyp_ops = {
.page_relinquish = gunyah_page_relinquish,
.post_page_relinquish_tlb_inv = gunyah_post_page_relinquish_tlb_inv
};
#endif
static int __init gunyah_guest_init(void)
{
struct addrspace_info_area_rootvm_addrspace_cap *info;
size_t size;
info = gunyah_get_info(GUNYAH_INFO_OWNER_ROOTVM, ADDRSPACE_INFO_AREA_ROOTVM_ADDRSPACE_CAP,
&size);
if (IS_ERR(info))
return PTR_ERR(info);
if (size != sizeof(*info))
return -EINVAL;
our_addrspace_capid = info->addrspace_cap;
#ifdef CONFIG_VIRTIO_BALLOON_HYP_OPS
virtio_balloon_hyp_ops = &gunyah_virtio_balloon_hyp_ops;
#endif
return 0;
}
core_initcall_sync(gunyah_guest_init);