2021-02-07 11:10:28 +08:00
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ACRN HSM : hypercalls of ACRN Hypervisor
*/
# ifndef __ACRN_HSM_HYPERCALL_H
# define __ACRN_HSM_HYPERCALL_H
# include <asm/acrn.h>
/*
* Hypercall IDs of the ACRN Hypervisor
*/
# define _HC_ID(x, y) (((x) << 24) | (y))
# define HC_ID 0x80UL
2021-02-07 11:10:39 +08:00
# define HC_ID_GEN_BASE 0x0UL
# define HC_SOS_REMOVE_CPU _HC_ID(HC_ID, HC_ID_GEN_BASE + 0x01)
2021-02-07 11:10:28 +08:00
# define HC_ID_VM_BASE 0x10UL
# define HC_CREATE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x00)
# define HC_DESTROY_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x01)
# define HC_START_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x02)
# define HC_PAUSE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x03)
# define HC_RESET_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x05)
2021-02-07 11:10:29 +08:00
# define HC_SET_VCPU_REGS _HC_ID(HC_ID, HC_ID_VM_BASE + 0x06)
2021-02-07 11:10:28 +08:00
2021-02-07 11:10:34 +08:00
# define HC_ID_IRQ_BASE 0x20UL
# define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03)
# define HC_VM_INTR_MONITOR _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x04)
# define HC_SET_IRQLINE _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x05)
virt: acrn: Introduce I/O request management
An I/O request of a User VM, which is constructed by the hypervisor, is
distributed by the ACRN Hypervisor Service Module to an I/O client
corresponding to the address range of the I/O request.
For each User VM, there is a shared 4-KByte memory region used for I/O
requests communication between the hypervisor and Service VM. An I/O
request is a 256-byte structure buffer, which is 'struct
acrn_io_request', that is filled by an I/O handler of the hypervisor
when a trapped I/O access happens in a User VM. ACRN userspace in the
Service VM first allocates a 4-KByte page and passes the GPA (Guest
Physical Address) of the buffer to the hypervisor. The buffer is used as
an array of 16 I/O request slots with each I/O request slot being 256
bytes. This array is indexed by vCPU ID.
An I/O client, which is 'struct acrn_ioreq_client', is responsible for
handling User VM I/O requests whose accessed GPA falls in a certain
range. Multiple I/O clients can be associated with each User VM. There
is a special client associated with each User VM, called the default
client, that handles all I/O requests that do not fit into the range of
any other I/O clients. The ACRN userspace acts as the default client for
each User VM.
The state transitions of a ACRN I/O request are as follows.
FREE -> PENDING -> PROCESSING -> COMPLETE -> FREE -> ...
FREE: this I/O request slot is empty
PENDING: a valid I/O request is pending in this slot
PROCESSING: the I/O request is being processed
COMPLETE: the I/O request has been processed
An I/O request in COMPLETE or FREE state is owned by the hypervisor. HSM
and ACRN userspace are in charge of processing the others.
The processing flow of I/O requests are listed as following:
a) The I/O handler of the hypervisor will fill an I/O request with
PENDING state when a trapped I/O access happens in a User VM.
b) The hypervisor makes an upcall, which is a notification interrupt, to
the Service VM.
c) The upcall handler schedules a worker to dispatch I/O requests.
d) The worker looks for the PENDING I/O requests, assigns them to
different registered clients based on the address of the I/O accesses,
updates their state to PROCESSING, and notifies the corresponding
client to handle.
e) The notified client handles the assigned I/O requests.
f) The HSM updates I/O requests states to COMPLETE and notifies the
hypervisor of the completion via hypercalls.
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Zhi Wang <zhi.a.wang@intel.com>
Cc: Zhenyu Wang <zhenyuw@linux.intel.com>
Cc: Yu Wang <yu1.wang@intel.com>
Cc: Reinette Chatre <reinette.chatre@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Zhi Wang <zhi.a.wang@intel.com>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Acked-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Shuo Liu <shuo.a.liu@intel.com>
Link: https://lore.kernel.org/r/20210207031040.49576-10-shuo.a.liu@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-07 11:10:31 +08:00
# define HC_ID_IOREQ_BASE 0x30UL
# define HC_SET_IOREQ_BUFFER _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x00)
# define HC_NOTIFY_REQUEST_FINISH _HC_ID(HC_ID, HC_ID_IOREQ_BASE + 0x01)
2021-02-07 11:10:30 +08:00
# define HC_ID_MEM_BASE 0x40UL
# define HC_VM_SET_MEMORY_REGIONS _HC_ID(HC_ID, HC_ID_MEM_BASE + 0x02)
2021-02-07 11:10:33 +08:00
# define HC_ID_PCI_BASE 0x50UL
# define HC_SET_PTDEV_INTR _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x03)
# define HC_RESET_PTDEV_INTR _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x04)
# define HC_ASSIGN_PCIDEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x05)
# define HC_DEASSIGN_PCIDEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x06)
2021-09-23 16:41:27 +08:00
# define HC_ASSIGN_MMIODEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x07)
# define HC_DEASSIGN_MMIODEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x08)
2021-09-23 16:41:28 +08:00
# define HC_CREATE_VDEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x09)
# define HC_DESTROY_VDEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0A)
2021-02-07 11:10:33 +08:00
2021-02-07 11:10:35 +08:00
# define HC_ID_PM_BASE 0x80UL
# define HC_PM_GET_CPU_STATE _HC_ID(HC_ID, HC_ID_PM_BASE + 0x00)
2021-02-07 11:10:39 +08:00
/**
* hcall_sos_remove_cpu ( ) - Remove a vCPU of Service VM
* @ cpu : The vCPU to be removed
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_sos_remove_cpu ( u64 cpu )
{
return acrn_hypercall1 ( HC_SOS_REMOVE_CPU , cpu ) ;
}
2021-02-07 11:10:28 +08:00
/**
* hcall_create_vm ( ) - Create a User VM
* @ vminfo : Service VM GPA of info of User VM creation
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_create_vm ( u64 vminfo )
{
return acrn_hypercall1 ( HC_CREATE_VM , vminfo ) ;
}
/**
* hcall_start_vm ( ) - Start a User VM
* @ vmid : User VM ID
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_start_vm ( u64 vmid )
{
return acrn_hypercall1 ( HC_START_VM , vmid ) ;
}
/**
* hcall_pause_vm ( ) - Pause a User VM
* @ vmid : User VM ID
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_pause_vm ( u64 vmid )
{
return acrn_hypercall1 ( HC_PAUSE_VM , vmid ) ;
}
/**
* hcall_destroy_vm ( ) - Destroy a User VM
* @ vmid : User VM ID
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_destroy_vm ( u64 vmid )
{
return acrn_hypercall1 ( HC_DESTROY_VM , vmid ) ;
}
/**
* hcall_reset_vm ( ) - Reset a User VM
* @ vmid : User VM ID
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_reset_vm ( u64 vmid )
{
return acrn_hypercall1 ( HC_RESET_VM , vmid ) ;
}
2021-02-07 11:10:29 +08:00
/**
* hcall_set_vcpu_regs ( ) - Set up registers of virtual CPU of a User VM
* @ vmid : User VM ID
* @ regs_state : Service VM GPA of registers state
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_set_vcpu_regs ( u64 vmid , u64 regs_state )
{
return acrn_hypercall2 ( HC_SET_VCPU_REGS , vmid , regs_state ) ;
}
2021-02-07 11:10:34 +08:00
/**
* hcall_inject_msi ( ) - Deliver a MSI interrupt to a User VM
* @ vmid : User VM ID
* @ msi : Service VM GPA of MSI message
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_inject_msi ( u64 vmid , u64 msi )
{
return acrn_hypercall2 ( HC_INJECT_MSI , vmid , msi ) ;
}
/**
* hcall_vm_intr_monitor ( ) - Set a shared page for User VM interrupt statistics
* @ vmid : User VM ID
* @ addr : Service VM GPA of the shared page
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_vm_intr_monitor ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_VM_INTR_MONITOR , vmid , addr ) ;
}
/**
* hcall_set_irqline ( ) - Set or clear an interrupt line
* @ vmid : User VM ID
* @ op : Service VM GPA of interrupt line operations
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_set_irqline ( u64 vmid , u64 op )
{
return acrn_hypercall2 ( HC_SET_IRQLINE , vmid , op ) ;
}
virt: acrn: Introduce I/O request management
An I/O request of a User VM, which is constructed by the hypervisor, is
distributed by the ACRN Hypervisor Service Module to an I/O client
corresponding to the address range of the I/O request.
For each User VM, there is a shared 4-KByte memory region used for I/O
requests communication between the hypervisor and Service VM. An I/O
request is a 256-byte structure buffer, which is 'struct
acrn_io_request', that is filled by an I/O handler of the hypervisor
when a trapped I/O access happens in a User VM. ACRN userspace in the
Service VM first allocates a 4-KByte page and passes the GPA (Guest
Physical Address) of the buffer to the hypervisor. The buffer is used as
an array of 16 I/O request slots with each I/O request slot being 256
bytes. This array is indexed by vCPU ID.
An I/O client, which is 'struct acrn_ioreq_client', is responsible for
handling User VM I/O requests whose accessed GPA falls in a certain
range. Multiple I/O clients can be associated with each User VM. There
is a special client associated with each User VM, called the default
client, that handles all I/O requests that do not fit into the range of
any other I/O clients. The ACRN userspace acts as the default client for
each User VM.
The state transitions of a ACRN I/O request are as follows.
FREE -> PENDING -> PROCESSING -> COMPLETE -> FREE -> ...
FREE: this I/O request slot is empty
PENDING: a valid I/O request is pending in this slot
PROCESSING: the I/O request is being processed
COMPLETE: the I/O request has been processed
An I/O request in COMPLETE or FREE state is owned by the hypervisor. HSM
and ACRN userspace are in charge of processing the others.
The processing flow of I/O requests are listed as following:
a) The I/O handler of the hypervisor will fill an I/O request with
PENDING state when a trapped I/O access happens in a User VM.
b) The hypervisor makes an upcall, which is a notification interrupt, to
the Service VM.
c) The upcall handler schedules a worker to dispatch I/O requests.
d) The worker looks for the PENDING I/O requests, assigns them to
different registered clients based on the address of the I/O accesses,
updates their state to PROCESSING, and notifies the corresponding
client to handle.
e) The notified client handles the assigned I/O requests.
f) The HSM updates I/O requests states to COMPLETE and notifies the
hypervisor of the completion via hypercalls.
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Zhi Wang <zhi.a.wang@intel.com>
Cc: Zhenyu Wang <zhenyuw@linux.intel.com>
Cc: Yu Wang <yu1.wang@intel.com>
Cc: Reinette Chatre <reinette.chatre@intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Zhi Wang <zhi.a.wang@intel.com>
Reviewed-by: Reinette Chatre <reinette.chatre@intel.com>
Acked-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Shuo Liu <shuo.a.liu@intel.com>
Link: https://lore.kernel.org/r/20210207031040.49576-10-shuo.a.liu@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-07 11:10:31 +08:00
/**
* hcall_set_ioreq_buffer ( ) - Set up the shared buffer for I / O Requests .
* @ vmid : User VM ID
* @ buffer : Service VM GPA of the shared buffer
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_set_ioreq_buffer ( u64 vmid , u64 buffer )
{
return acrn_hypercall2 ( HC_SET_IOREQ_BUFFER , vmid , buffer ) ;
}
/**
* hcall_notify_req_finish ( ) - Notify ACRN Hypervisor of I / O request completion .
* @ vmid : User VM ID
* @ vcpu : The vCPU which initiated the I / O request
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_notify_req_finish ( u64 vmid , u64 vcpu )
{
return acrn_hypercall2 ( HC_NOTIFY_REQUEST_FINISH , vmid , vcpu ) ;
}
2021-02-07 11:10:30 +08:00
/**
* hcall_set_memory_regions ( ) - Inform the hypervisor to set up EPT mappings
* @ regions_pa : Service VM GPA of & struct vm_memory_region_batch
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_set_memory_regions ( u64 regions_pa )
{
return acrn_hypercall1 ( HC_VM_SET_MEMORY_REGIONS , regions_pa ) ;
}
2021-09-23 16:41:28 +08:00
/**
* hcall_create_vdev ( ) - Create a virtual device for a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_vdev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_create_vdev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_CREATE_VDEV , vmid , addr ) ;
}
/**
* hcall_destroy_vdev ( ) - Destroy a virtual device of a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_vdev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_destroy_vdev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_DESTROY_VDEV , vmid , addr ) ;
}
2021-09-23 16:41:27 +08:00
/**
* hcall_assign_mmiodev ( ) - Assign a MMIO device to a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_mmiodev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_assign_mmiodev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_ASSIGN_MMIODEV , vmid , addr ) ;
}
/**
* hcall_deassign_mmiodev ( ) - De - assign a PCI device from a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_mmiodev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_deassign_mmiodev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_DEASSIGN_MMIODEV , vmid , addr ) ;
}
2021-02-07 11:10:33 +08:00
/**
* hcall_assign_pcidev ( ) - Assign a PCI device to a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_pcidev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_assign_pcidev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_ASSIGN_PCIDEV , vmid , addr ) ;
}
/**
* hcall_deassign_pcidev ( ) - De - assign a PCI device from a User VM
* @ vmid : User VM ID
* @ addr : Service VM GPA of the & struct acrn_pcidev
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_deassign_pcidev ( u64 vmid , u64 addr )
{
return acrn_hypercall2 ( HC_DEASSIGN_PCIDEV , vmid , addr ) ;
}
/**
* hcall_set_ptdev_intr ( ) - Configure an interrupt for an assigned PCI device .
* @ vmid : User VM ID
* @ irq : Service VM GPA of the & struct acrn_ptdev_irq
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_set_ptdev_intr ( u64 vmid , u64 irq )
{
return acrn_hypercall2 ( HC_SET_PTDEV_INTR , vmid , irq ) ;
}
/**
* hcall_reset_ptdev_intr ( ) - Reset an interrupt for an assigned PCI device .
* @ vmid : User VM ID
* @ irq : Service VM GPA of the & struct acrn_ptdev_irq
*
* Return : 0 on success , < 0 on failure
*/
static inline long hcall_reset_ptdev_intr ( u64 vmid , u64 irq )
{
return acrn_hypercall2 ( HC_RESET_PTDEV_INTR , vmid , irq ) ;
}
2021-02-07 11:10:35 +08:00
/*
* hcall_get_cpu_state ( ) - Get P - states and C - states info from the hypervisor
* @ state : Service VM GPA of buffer of P - states and C - states
*/
static inline long hcall_get_cpu_state ( u64 cmd , u64 state )
{
return acrn_hypercall2 ( HC_PM_GET_CPU_STATE , cmd , state ) ;
}
2021-02-07 11:10:28 +08:00
# endif /* __ACRN_HSM_HYPERCALL_H */