android_kernel_msm-6.1_noth.../include/linux/gzvm_drv.h
Yi-De Wu 7cc3767c2a FROMLIST: virt: geniezone: Add block-based demand paging support
To balance memory usage and performance, GenieZone supports larger
granularity demand paging, called block-based demand paging.
Gzvm driver uses enable_cap to query the hypervisor if it supports
block-based demand paging and the given granularity or not. Meanwhile,
the gzvm driver allocates a shared buffer for storing the physical
pages later.

If the hypervisor supports, every time the gzvm driver handles guest
page faults, it allocates more memory in advance (default: 2MB) for
demand paging. And fills those physical pages into the allocated shared
memory, then calls the hypervisor to map to guest's memory.

The physical pages allocated for block-based demand paging is not
necessary to be contiguous because in many cases, 2MB block is not
followed. 1st, the memory is allocated because of VMM's page fault
(VMM loads kernel image to guest memory before running). In this case,
the page is allocated by the host kernel and using PAGE_SIZE. 2nd is
that guest may return memory to host via ballooning and that is still
4KB (or PAGE_SIZE) granularity. Therefore, we do not have to allocate
physically contiguous 2MB pages.

Change-Id: Id101da5a8ff73dbf5c9a3ab03526cdf5d2f6006e
Signed-off-by: Yingshiuan Pan <yingshiuan.pan@mediatek.com>
Signed-off-by: kevenny hsieh <kevenny.hsieh@mediatek.com>
Signed-off-by: Liju-Clr Chen <liju-clr.chen@mediatek.com>
Signed-off-by: Yi-De Wu <yi-de.wu@mediatek.com>
Bug: 301179926
Link: https://lore.kernel.org/all/20230919111210.19615-16-yi-de.wu@mediatek.com/
2023-10-20 16:31:15 +00:00

190 lines
5.9 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 MediaTek Inc.
*/
#ifndef __GZVM_DRV_H__
#define __GZVM_DRV_H__
#include <linux/eventfd.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/gzvm.h>
#include <linux/srcu.h>
/*
* For the normal physical address, the highest 12 bits should be zero, so we
* can mask bit 62 ~ bit 52 to indicate the error physical address
*/
#define GZVM_PA_ERR_BAD (0x7ffULL << 52)
#define GZVM_VCPU_MMAP_SIZE PAGE_SIZE
#define INVALID_VM_ID 0xffff
/*
* These are the definitions of APIs between GenieZone hypervisor and driver,
* there's no need to be visible to uapi. Furthermore, we need GenieZone
* specific error code in order to map to Linux errno
*/
#define NO_ERROR (0)
#define ERR_NO_MEMORY (-5)
#define ERR_INVALID_ARGS (-8)
#define ERR_NOT_SUPPORTED (-24)
#define ERR_NOT_IMPLEMENTED (-27)
#define ERR_FAULT (-40)
#define GZVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
/*
* The following data structures are for data transferring between driver and
* hypervisor, and they're aligned with hypervisor definitions
*/
#define GZVM_MAX_VCPUS 8
#define GZVM_MAX_MEM_REGION 10
#define GZVM_VCPU_RUN_MAP_SIZE (PAGE_SIZE * 2)
#define GZVM_BLOCK_BASED_DEMAND_PAGE_SIZE (2 * 1024 * 1024) /* 2MB */
/* struct mem_region_addr_range - Identical to ffa memory constituent */
struct mem_region_addr_range {
/* the base IPA of the constituent memory region, aligned to 4 kiB */
__u64 address;
/* the number of 4 kiB pages in the constituent memory region. */
__u32 pg_cnt;
__u32 reserved;
};
struct gzvm_memory_region_ranges {
__u32 slot;
__u32 constituent_cnt;
__u64 total_pages;
__u64 gpa;
struct mem_region_addr_range constituents[];
};
/* struct gzvm_memslot - VM's memory slot descriptor */
struct gzvm_memslot {
u64 base_gfn; /* begin of guest page frame */
unsigned long npages; /* number of pages this slot covers */
unsigned long userspace_addr; /* corresponding userspace va */
struct vm_area_struct *vma; /* vma related to this userspace addr */
u32 flags;
u32 slot_id;
};
struct gzvm_vcpu {
struct gzvm *gzvm;
int vcpuid;
/* lock of vcpu*/
struct mutex lock;
struct gzvm_vcpu_run *run;
struct gzvm_vcpu_hwstate *hwstate;
};
struct gzvm {
struct gzvm_vcpu *vcpus[GZVM_MAX_VCPUS];
/* userspace tied to this vm */
struct mm_struct *mm;
struct gzvm_memslot memslot[GZVM_MAX_MEM_REGION];
/* lock for list_add*/
struct mutex lock;
struct {
/* lock for irqfds list operation */
spinlock_t lock;
struct list_head items;
struct list_head resampler_list;
/* lock for irqfds resampler */
struct mutex resampler_lock;
} irqfds;
struct list_head ioevents;
struct list_head vm_list;
u16 vm_id;
struct hlist_head irq_ack_notifier_list;
struct srcu_struct irq_srcu;
/* lock for irq injection */
struct mutex irq_lock;
/*
* demand page granularity: how much memory we allocate for VM in a
* single page fault
*/
u32 demand_page_gran;
/* the mailbox for transferring large portion pages */
u64 *demand_page_buffer;
/*
* lock for preventing multiple cpu using the same demand page mailbox
* at the same time
*/
struct mutex demand_paging_lock;
};
long gzvm_dev_ioctl_check_extension(struct gzvm *gzvm, unsigned long args);
int gzvm_dev_ioctl_create_vm(unsigned long vm_type);
int gzvm_err_to_errno(unsigned long err);
void gzvm_destroy_all_vms(void);
void gzvm_destroy_vcpus(struct gzvm *gzvm);
/* arch-dependant functions */
int gzvm_arch_probe(void);
int gzvm_arch_set_memregion(u16 vm_id, size_t buf_size,
phys_addr_t region);
int gzvm_arch_check_extension(struct gzvm *gzvm, __u64 cap, void __user *argp);
int gzvm_arch_create_vm(unsigned long vm_type);
int gzvm_arch_destroy_vm(u16 vm_id);
int gzvm_arch_map_guest(u16 vm_id, int memslot_id, u64 pfn, u64 gfn,
u64 nr_pages);
int gzvm_arch_map_guest_block(u16 vm_id, int memslot_id, u64 gfn, u64 nr_pages);
int gzvm_vm_ioctl_arch_enable_cap(struct gzvm *gzvm,
struct gzvm_enable_cap *cap,
void __user *argp);
u64 gzvm_hva_to_pa_arch(u64 hva);
int gzvm_vm_ioctl_create_vcpu(struct gzvm *gzvm, u32 cpuid);
int gzvm_arch_vcpu_update_one_reg(struct gzvm_vcpu *vcpu, __u64 reg_id,
bool is_write, __u64 *data);
int gzvm_arch_create_vcpu(u16 vm_id, int vcpuid, void *run);
int gzvm_arch_vcpu_run(struct gzvm_vcpu *vcpu, __u64 *exit_reason);
int gzvm_arch_destroy_vcpu(u16 vm_id, int vcpuid);
int gzvm_arch_inform_exit(u16 vm_id);
u64 gzvm_gfn_to_hva_memslot(struct gzvm_memslot *memslot, u64 gfn);
u64 hva_to_pa_fast(u64 hva);
u64 hva_to_pa_slow(u64 hva);
int gzvm_gfn_to_pfn_memslot(struct gzvm_memslot *memslot, u64 gfn, u64 *pfn);
int gzvm_find_memslot(struct gzvm *vm, u64 gpa);
int gzvm_handle_page_fault(struct gzvm_vcpu *vcpu);
bool gzvm_handle_guest_exception(struct gzvm_vcpu *vcpu);
int gzvm_arch_create_device(u16 vm_id, struct gzvm_create_device *gzvm_dev);
int gzvm_arch_inject_irq(struct gzvm *gzvm, unsigned int vcpu_idx,
u32 irq, bool level);
void gzvm_notify_acked_irq(struct gzvm *gzvm, unsigned int gsi);
int gzvm_irqfd(struct gzvm *gzvm, struct gzvm_irqfd *args);
int gzvm_drv_irqfd_init(void);
void gzvm_drv_irqfd_exit(void);
int gzvm_vm_irqfd_init(struct gzvm *gzvm);
void gzvm_vm_irqfd_release(struct gzvm *gzvm);
int gzvm_arch_memregion_purpose(struct gzvm *gzvm,
struct gzvm_userspace_memory_region *mem);
int gzvm_arch_set_dtb_config(struct gzvm *gzvm, struct gzvm_dtb_config *args);
int gzvm_init_ioeventfd(struct gzvm *gzvm);
int gzvm_ioeventfd(struct gzvm *gzvm, struct gzvm_ioeventfd *args);
bool gzvm_ioevent_write(struct gzvm_vcpu *vcpu, __u64 addr, int len,
const void *val);
void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt);
struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr);
void add_wait_queue_priority(struct wait_queue_head *wq_head,
struct wait_queue_entry *wq_entry);
#endif /* __GZVM_DRV_H__ */