Files
2025-08-12 22:16:57 +02:00

230 lines
7.9 KiB
C
Executable File

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef _GUNYAH_VM_MGR_PRIV_H
#define _GUNYAH_VM_MGR_PRIV_H
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/maple_tree.h>
#include <linux/mutex.h>
#include <linux/pagemap.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/set_memory.h>
#include <linux/wait.h>
#include <uapi/linux/gunyah.h>
#include "rsc_mgr.h"
enum gunyah_vm_mem_share_type {
VM_MEM_SHARE,
VM_MEM_LEND,
};
struct gunyah_vm_gup_binding {
enum gunyah_vm_mem_share_type share_type;
u64 guest_phys_addr;
u64 userspace_addr;
u64 size;
u32 flags;
};
static inline u64 gunyah_gpa_to_gfn(u64 gpa)
{
return gpa >> PAGE_SHIFT;
}
static inline u64 gunyah_gfn_to_gpa(u64 gfn)
{
return gfn << PAGE_SHIFT;
}
long gunyah_dev_vm_mgr_ioctl(struct gunyah_rm *rm, unsigned int cmd,
unsigned long arg);
/**
* struct gunyah_vm - Main representation of a Gunyah Virtual machine
* @vmid: Gunyah's VMID for this virtual machine
* @mm: A maple tree of all memory that has been mapped to a VM.
* Indices are guest frame numbers; entries are either folios or
* RM mem parcels
* @bindings: A maple tree of guest memfd bindings. Indices are guest frame
* numbers; entries are &struct gunyah_gmem_binding
* @bindings_lock: For serialization to @bindings
* @mm_s: Userspace tied to this vm
* @addrspace_ticket: Resource ticket to the capability for guest VM's
* address space
* @host_private_extent_ticket: Resource ticket to the capability for our
* memory extent from which to lend private
* memory to the guest
* @host_shared_extent_ticket: Resource ticket to the capaiblity for our
* memory extent from which to share memory
* with the guest. Distinction with
* @host_private_extent_ticket needed for
* current Qualcomm platforms; on non-Qualcomm
* platforms, this is the same capability ID
* @guest_private_extent_ticket: Resource ticket to the capaiblity for
* the guest's memory extent to lend private
* memory to
* @guest_shared_extent_ticket: Resource ticket to the capability for
* the memory extent that represents
* memory shared with the guest.
* @mmio_handler_root: RB tree of MMIO handlers.
* Entries are &struct gunyah_vm_io_handler
* @mmio_handler_lock: Serialization of traversing @mmio_handler_root
* @rm: Pointer to the resource manager struct to make RM calls
* @parent: For logging
* @nb: Notifier block for RM notifications
* @vm_status: Current state of the VM, as last reported by RM
* @vm_status_wait: Wait queue for status @vm_status changes
* @status_lock: Serializing state transitions
* @exit_info: Breadcrumbs why VM is not running anymore
* @kref: Reference counter for VM functions
* @fn_lock: Serialization addition of functions
* @functions: List of &struct gunyah_vm_function_instance that have been
* created by user for this VM.
* @resource_lock: Serializing addition of resources and resource tickets
* @resources: List of &struct gunyah_resource that are associated with this VM
* @resource_tickets: List of &struct gunyah_vm_resource_ticket
* @auth: Authentication mechanism to be used by resource manager when
* launching the VM
* @dtb: For tracking dtb configuration when launching the VM
* @dtb.config: Location of the DTB in the guest memory
* @dtb.parcel_start: Guest frame number where the memory parcel that we lent to
* VM (DTB could start in middle of folio; we lend entire
* folio; parcel_start is start of the folio)
* @dtb.parcel_pages: Number of pages lent for the memory parcel
* @dtb.parcel: Data for resource manager to lend the parcel
* @boot_context: Requested initial boot context to set when launching the VM
*
* Members are grouped by hot path.
*/
struct gunyah_vm {
u16 vmid;
struct maple_tree mm;
struct maple_tree bindings;
struct rw_semaphore bindings_lock;
struct mm_struct *mm_s;
struct gunyah_vm_resource_ticket addrspace_ticket,
host_private_extent_ticket, host_shared_extent_ticket,
guest_private_extent_ticket, guest_shared_extent_ticket;
struct rb_root mmio_handler_root;
struct rw_semaphore mmio_handler_lock;
struct gunyah_rm *rm;
struct notifier_block nb;
enum gunyah_rm_vm_status vm_status;
wait_queue_head_t vm_status_wait;
struct rw_semaphore status_lock;
struct gunyah_vm_exit_info exit_info;
struct kref kref;
struct mutex fn_lock;
struct list_head functions;
struct mutex resources_lock;
struct list_head resources;
struct list_head resource_tickets;
struct device *parent;
enum gunyah_rm_vm_auth_mechanism auth;
struct {
struct gunyah_vm_dtb_config config;
u64 parcel_start, parcel_pages;
struct gunyah_rm_mem_parcel parcel;
} dtb;
struct {
struct gunyah_vm_firmware_config config;
u64 parcel_start, parcel_pages;
struct gunyah_rm_mem_parcel parcel;
} fw;
struct xarray boot_context;
};
int gunyah_vm_mmio_write(struct gunyah_vm *ghvm, u64 addr, u32 len, u64 data);
/**
* folio_mmapped() - Returns true if the folio is mapped into any vma
* @folio: Folio to test
*/
static bool folio_mmapped(struct folio *folio)
{
struct address_space *mapping = folio->mapping;
struct vm_area_struct *vma;
bool ret = false;
i_mmap_lock_read(mapping);
vma_interval_tree_foreach(vma, &mapping->i_mmap, folio_index(folio),
folio_index(folio) + folio_nr_pages(folio)) {
ret = true;
break;
}
i_mmap_unlock_read(mapping);
return ret;
}
/**
* gunyah_folio_lend_safe() - Returns true if folio is ready to be lent to guest
* @folio: Folio to prepare
*
* Tests if the folio is mapped anywhere outside the kernel logical map
* and whether any userspace has a vma containing the folio, even if it hasn't
* paged it in. We want to avoid causing fault to userspace.
* If userspace doesn't have it mapped anywhere, then unmap from kernel
* logical map to prevent accidental access (e.g. by load_unaligned_zeropad)
*/
static inline bool gunyah_folio_lend_safe(struct folio *folio)
{
long i;
if (folio_mapped(folio) || folio_mmapped(folio))
return false;
for (i = 0; i < folio_nr_pages(folio); i++)
set_direct_map_invalid_noflush(folio_page(folio, i));
/**
* No need to flush tlb on armv8/9: hypervisor will flush when it
* removes from our stage 2
*/
return true;
}
/**
* gunyah_folio_host_reclaim() - Restores kernel logical map to folio
* @folio: folio to reclaim by host
*
* See also gunyah_folio_lend_safe().
*/
static inline void gunyah_folio_host_reclaim(struct folio *folio)
{
long i;
for (i = 0; i < folio_nr_pages(folio); i++)
set_direct_map_default_noflush(folio_page(folio, i));
}
int gunyah_vm_parcel_to_paged(struct gunyah_vm *ghvm,
struct gunyah_rm_mem_parcel *parcel, u64 gfn,
u64 nr);
void gunyah_vm_mm_erase_range(struct gunyah_vm *ghvm, u64 gfn, u64 nr);
int gunyah_vm_reclaim_parcel(struct gunyah_vm *ghvm,
struct gunyah_rm_mem_parcel *parcel, u64 gfn);
int gunyah_vm_provide_folio(struct gunyah_vm *ghvm, struct folio *folio,
u64 gfn, bool share, bool write);
int gunyah_vm_reclaim_folio(struct gunyah_vm *ghvm, u64 gfn, struct folio *folio);
int gunyah_vm_reclaim_range(struct gunyah_vm *ghvm, u64 gfn, u64 nr);
int gunyah_vm_binding_alloc(struct gunyah_vm *ghvm,
struct gunyah_userspace_memory_region *region,
bool lend);
int gunyah_gup_setup_demand_paging(struct gunyah_vm *ghvm);
int gunyah_gup_share_parcel(struct gunyah_vm *ghvm,
struct gunyah_rm_mem_parcel *parcel,
u64 *gfn, u64 *nr);
int gunyah_gup_demand_page(struct gunyah_vm *ghvm, u64 gpa, bool write);
#endif