virt: acrn: Introduce interfaces for PIO region passthrough

PIO region passthrough enables an OS in a virtual machine to directly
access a PIO device in the host. It promises almost the native
performance, which is required in performance-critical scenarios of
ACRN.

ACRN hypervisor will pass through most resource to Service VM at the
begining except those pre-allocated to hypervisor itself and pre-launched
VM. GPA and HPA of all these passthrough resource are identical mapped in
Service VM. In this case, user space program can manipulate the PIO region
in Service VM as PIO region in Host, such as delivering GPA in Service VM
to hypervisor to assign PIO region to other post launched VM.

HSM provides the following ioctls:
  - Assign - ACRN_IOCTL_ASSIGN_PIO_REGION
    Pass data struct acrn_pio_region from userspace to the hypervisor, and
    inform the hypervisor to assign a PIO region to a User VM.

  - De-assign - ACRN_IOCTL_DEASSIGN_PIO_REGION
    Pass data struct acrn_pio_region from userspace to the hypervisor, and
    inform the hypervisor to de-assign a PIO region from a User VM.

These hypercalls are for ACPI device passthrough function of ACRN.
Now ACRN only support legacy UART which has a PIO region. Before passing
through this PIO region to a post-launched VM, ACRN device model would
unbind UART device from Service VM through sysfs node
/sys/bus/pnp/drivers/serial/unbind.

Tracked-On: projectacrn/acrn-hypervisor#8635

Signed-off-by: Yichong Tang <yichong.tang@intel.com>
This commit is contained in:
yichongt 2024-06-25 17:41:36 +08:00 committed by wenlingz
parent 51b9a968e5
commit 7159ad071b
3 changed files with 71 additions and 0 deletions

View File

@ -116,6 +116,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
struct acrn_ioeventfd ioeventfd;
struct acrn_vm_memmap memmap;
struct acrn_mmiodev *mmiodev;
struct acrn_pio_region *pio_region;
struct acrn_msi_entry *msi;
struct acrn_pcidev *pcidev;
struct acrn_irqfd irqfd;
@ -331,6 +332,30 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
"Failed to reset intr for ptdev!\n");
kfree(irq_info);
break;
case ACRN_IOCTL_ASSIGN_PIO_REGION:
pio_region = memdup_user((void __user *)ioctl_param,
sizeof(struct acrn_pio_region));
if (IS_ERR(pio_region))
return PTR_ERR(pio_region);
ret = hcall_assign_pio_region(vm->vmid, virt_to_phys(pio_region));
if (ret < 0)
dev_dbg(acrn_dev.this_device,
"Failed to assign PIO resource!\n");
kfree(pio_region);
break;
case ACRN_IOCTL_DEASSIGN_PIO_REGION:
pio_region = memdup_user((void __user *)ioctl_param,
sizeof(struct acrn_pio_region));
if (IS_ERR(pio_region))
return PTR_ERR(pio_region);
ret = hcall_deassign_pio_region(vm->vmid, virt_to_phys(pio_region));
if (ret < 0)
dev_dbg(acrn_dev.this_device,
"Failed to deassign PIO resource!\n");
kfree(pio_region);
break;
case ACRN_IOCTL_SET_IRQLINE:
ret = hcall_set_irqline(vm->vmid, ioctl_param);
if (ret < 0)

View File

@ -48,6 +48,8 @@
#define HC_DEASSIGN_MMIODEV _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x08)
#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)
#define HC_ASSIGN_PIO_REGION _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0B)
#define HC_DEASSIGN_PIO_REGION _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0C)
#define HC_ID_DBG_BASE 0x60UL
#define HC_SETUP_SBUF _HC_ID(HC_ID, HC_ID_DBG_BASE + 0x00)
@ -328,6 +330,30 @@ static inline long hcall_reset_ptdev_intr(u64 vmid, u64 irq)
return acrn_hypercall2(HC_RESET_PTDEV_INTR, vmid, irq);
}
/**
* hcall_assign_pio_region() - Assign a PIO region to a User VM
* @vmid: User VM ID
* @addr: Service VM GPA of the &struct acrn_pio_region
*
* Return: 0 on success, <0 on failure
*/
static inline long hcall_assign_pio_region(u64 vmid, u64 addr)
{
return acrn_hypercall2(HC_ASSIGN_PIO_REGION, vmid, addr);
}
/**
* hcall_deassign_pio_region() - De-assign a PIO region from a User VM
* @vmid: User VM ID
* @addr: Service VM GPA of the &struct acrn_pio_region
*
* Return: 0 on success, <0 on failure
*/
static inline long hcall_deassign_pio_region(u64 vmid, u64 addr)
{
return acrn_hypercall2(HC_DEASSIGN_PIO_REGION, vmid, addr);
}
/*
* 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

View File

@ -441,6 +441,22 @@ struct acrn_mmiodev {
} res[ACRN_MMIODEV_RES_NUM];
};
/**
* struct acrn_pio_region - Info for assigning or de-assigning a PIO region
* @name: Name of the PIO device.
* @res[].port_address: Physical address of PIO region.
* @res[].size: Size of the PIO region for the PIO device.
*
* This structure will be passed to hypervisor directly.
*/
struct acrn_pio_region {
__u8 name[8];
struct {
__u16 port_address;
__u16 size;
} res;
};
/**
* struct acrn_vdev - Info for creating or destroying a virtual device
* @id: Union of identifier of the virtual device
@ -724,6 +740,10 @@ struct sbuf_setup_param {
_IOW(ACRN_IOCTL_TYPE, 0x59, struct acrn_vdev)
#define ACRN_IOCTL_DESTROY_VDEV \
_IOW(ACRN_IOCTL_TYPE, 0x5A, struct acrn_vdev)
#define ACRN_IOCTL_ASSIGN_PIO_REGION \
_IOW(ACRN_IOCTL_TYPE, 0x5B, struct acrn_pio_region)
#define ACRN_IOCTL_DEASSIGN_PIO_REGION \
_IOW(ACRN_IOCTL_TYPE, 0x5C, struct acrn_pio_region)
#define ACRN_IOCTL_PM_GET_CPU_STATE \
_IOWR(ACRN_IOCTL_TYPE, 0x60, __u64)