mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-22 05:30:24 +00:00
hv: pio_region: add hypercalls to support pio device pass through
Add two hypercalls HC_ASSIGN_PIO_REGION and HC_DEASSIGN_PIO_REGION to support PIO device pass through for post-launched VM. Add has_direct_pio_access function to check the pio access state of VM before allow/deny guest pio access. Align querying, setting and clearing interfaces of VM io.bitmap with general bitmap operation function. Tracked-On: #8635 Signed-off-by: Yichong Tang <yichong.tang@intel.com> Reviewed-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
fb2acbacb1
commit
b138dd1eaf
@ -82,6 +82,10 @@ static const struct hc_dispatch hc_dispatch_table[] = {
|
||||
.handler = hcall_add_vdev},
|
||||
[HC_IDX(HC_REMOVE_VDEV)] = {
|
||||
.handler = hcall_remove_vdev},
|
||||
[HC_IDX(HC_ASSIGN_PIO_REGION)] = {
|
||||
.handler = hcall_assign_pio_region},
|
||||
[HC_IDX(HC_DEASSIGN_PIO_REGION)] = {
|
||||
.handler = hcall_deassign_pio_region},
|
||||
[HC_IDX(HC_SET_PTDEV_INTR_INFO)] = {
|
||||
.handler = hcall_set_ptdev_intr_info},
|
||||
[HC_IDX(HC_RESET_PTDEV_INTR_INFO)] = {
|
||||
|
@ -204,7 +204,7 @@ void allow_guest_pio_access(struct acrn_vm *vm, uint16_t port_address,
|
||||
|
||||
b = (uint32_t *)vm->arch_vm.io_bitmap;
|
||||
for (i = 0U; i < nbytes; i++) {
|
||||
b[address >> 5U] &= ~(1U << (address & 0x1fU));
|
||||
bitmap32_clear_nolock(address & 0x1fU, &b[address >> 5U]);
|
||||
address++;
|
||||
}
|
||||
}
|
||||
@ -218,7 +218,35 @@ void deny_guest_pio_access(struct acrn_vm *vm, uint16_t port_address,
|
||||
|
||||
b = (uint32_t *)vm->arch_vm.io_bitmap;
|
||||
for (i = 0U; i < nbytes; i++) {
|
||||
b[address >> 5U] |= (1U << (address & 0x1fU));
|
||||
bitmap32_set_nolock(address & 0x1fU, &b[address >> 5U]);
|
||||
address++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a VM has full access to a port I/O range
|
||||
*
|
||||
* This API check if given \p vm has direct access to the port I/O space
|
||||
* starting from \p port_address to \p port_address + \p nbytes - 1.
|
||||
*
|
||||
* @param vm The VM whose port I/O access permissions is to be checked
|
||||
* @param port_address The start address of the port I/O range
|
||||
* @param nbytes The size of the range, in bytes
|
||||
*/
|
||||
bool has_direct_pio_access(struct acrn_vm *vm, uint16_t port_address, uint32_t nbytes)
|
||||
{
|
||||
uint16_t address = port_address;
|
||||
uint32_t *b;
|
||||
uint32_t i;
|
||||
bool ret = true;
|
||||
|
||||
b = (uint32_t *)vm->arch_vm.io_bitmap;
|
||||
for (i = 0U; i < nbytes; i++) {
|
||||
if (bitmap32_test(address & 0x1fU, &b[address >> 5U])) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
address++;
|
||||
}
|
||||
return ret;
|
||||
}
|
@ -1354,3 +1354,75 @@ int32_t hcall_remove_vdev(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, __u
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assign PIO device resource to a VM.
|
||||
*
|
||||
* @param vcpu Pointer to vCPU that initiates the hypercall
|
||||
* @param target_vm Pointer to target VM data structure
|
||||
* @param param2 guest physical address. This gpa points to data structure of
|
||||
* acrn_pio_region including assign PIO resource info
|
||||
*
|
||||
* @pre is_service_vm(vcpu->vm)
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
int32_t hcall_assign_pio_region(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm,
|
||||
__unused uint64_t param1, uint64_t param2)
|
||||
{
|
||||
struct acrn_vm *vm = vcpu->vm;
|
||||
int32_t ret = -EINVAL;
|
||||
struct acrn_pio_region pio_region;
|
||||
|
||||
/* We should only assign a device to a post-launched VM at creating time for safety, not runtime or other cases*/
|
||||
if (is_created_vm(target_vm)) {
|
||||
if (copy_from_gpa(vm, &pio_region, param2, sizeof(pio_region)) == 0) {
|
||||
if (has_direct_pio_access(vm, pio_region.res.port_address, pio_region.res.size)) {
|
||||
deny_guest_pio_access(vm, pio_region.res.port_address, pio_region.res.size);
|
||||
allow_guest_pio_access(target_vm, pio_region.res.port_address, pio_region.res.size);
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_err("vm[%d] %s failed: pio region not fully accessible for vm[%d].\n",target_vm->vm_id, __func__, vm->vm_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_err("vm[%d] %s failed: target vm not created.\n",target_vm->vm_id, __func__);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deassign PIO device resource from a VM.
|
||||
*
|
||||
* @param vcpu Pointer to vCPU that initiates the hypercall
|
||||
* @param target_vm Pointer to target VM data structure
|
||||
* @param param2 guest physical address. This gpa points to data structure of
|
||||
* acrn_pio_region including deassign PIO device info
|
||||
*
|
||||
* @pre is_service_vm(vcpu->vm)
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
int32_t hcall_deassign_pio_region(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm,
|
||||
__unused uint64_t param1, uint64_t param2)
|
||||
{
|
||||
struct acrn_vm *vm = vcpu->vm;
|
||||
int32_t ret = -EINVAL;
|
||||
struct acrn_pio_region pio_region;
|
||||
|
||||
/* We should only de-assign a device from a post-launched VM at creating/shutdown/reset time */
|
||||
if ((is_paused_vm(target_vm) || is_created_vm(target_vm))) {
|
||||
if (copy_from_gpa(vm, &pio_region, param2, sizeof(pio_region)) == 0) {
|
||||
if (has_direct_pio_access(target_vm, pio_region.res.port_address, pio_region.res.size)) {
|
||||
deny_guest_pio_access(target_vm, pio_region.res.port_address, pio_region.res.size);
|
||||
allow_guest_pio_access(vm, pio_region.res.port_address, pio_region.res.size);
|
||||
ret = 0;
|
||||
} else {
|
||||
pr_err("vm[%d] %s failed: pio region not fully accessible for vm[%d].\n",vm->vm_id, __func__, target_vm->vm_id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pr_err("vm[%d] %s failed: target vm not created or not paused.\n",target_vm->vm_id, __func__);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -80,6 +80,18 @@ void allow_guest_pio_access(struct acrn_vm *vm, uint16_t port_address, uint32_
|
||||
*/
|
||||
void deny_guest_pio_access(struct acrn_vm *vm, uint16_t port_address, uint32_t nbytes);
|
||||
|
||||
/**
|
||||
* @brief Check if a VM has full access to a port I/O range
|
||||
*
|
||||
* This API check if given \p vm has direct access to the port I/O space
|
||||
* starting from \p port_address to \p port_address + \p nbytes - 1.
|
||||
*
|
||||
* @param vm The VM whose port I/O access permissions is to be checked
|
||||
* @param port_address The start address of the port I/O range
|
||||
* @param nbytes The size of the range, in bytes
|
||||
*/
|
||||
bool has_direct_pio_access(struct acrn_vm *vm, uint16_t port_address, uint32_t nbytes);
|
||||
|
||||
/**
|
||||
* @brief Fire HSM interrupt to Service VM
|
||||
*/
|
||||
|
@ -346,6 +346,34 @@ int32_t hcall_add_vdev(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64
|
||||
*/
|
||||
int32_t hcall_remove_vdev(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64_t param1, uint64_t param2);
|
||||
|
||||
/**
|
||||
* @brief Assign PIO device resource to VM.
|
||||
*
|
||||
* @param vcpu Pointer to vCPU that initiates the hypercall
|
||||
* @param target_vm Pointer to target VM data structure
|
||||
* @param param1 not used
|
||||
* @param param2 guest physical address. This gpa points to data structure of
|
||||
* acrn_mmiores including assign PIO device resource info
|
||||
*
|
||||
* @pre is_service_vm(vcpu->vm)
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
int32_t hcall_assign_pio_region(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64_t param1, uint64_t param2);
|
||||
|
||||
/**
|
||||
* @brief Deassign PIO device resource from VM.
|
||||
*
|
||||
* @param vcpu Pointer to vCPU that initiates the hypercall
|
||||
* @param target_vm Pointer to target VM data structure
|
||||
* @param param1 not used
|
||||
* @param param2 guest physical address. This gpa points to data structure of
|
||||
* acrn_mmiores including assign PIO device resource info
|
||||
*
|
||||
* @pre is_service_vm(vcpu->vm)
|
||||
* @return 0 on success, non-zero on error.
|
||||
*/
|
||||
int32_t hcall_deassign_pio_region(struct acrn_vcpu *vcpu, struct acrn_vm *target_vm, uint64_t param1, uint64_t param2);
|
||||
|
||||
/**
|
||||
* @brief Set interrupt mapping info of ptdev.
|
||||
*
|
||||
|
@ -707,6 +707,19 @@ struct acrn_mmiodev {
|
||||
} res[MMIODEV_RES_NUM];
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Info to assign or deassign a PIO device for a VM
|
||||
*/
|
||||
struct acrn_pio_region {
|
||||
char name[8];
|
||||
struct acrn_piores {
|
||||
/** the io port address for PIO device */
|
||||
uint16_t port_address;
|
||||
/** the size of the io port for the PIO resource */
|
||||
uint16_t size;
|
||||
} res;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Info to create or destroy a virtual PCI or legacy device for a VM
|
||||
*
|
||||
|
@ -74,6 +74,8 @@
|
||||
#define HC_DEASSIGN_MMIODEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x08UL)
|
||||
#define HC_ADD_VDEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x09UL)
|
||||
#define HC_REMOVE_VDEV BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0AUL)
|
||||
#define HC_ASSIGN_PIO_REGION BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0BUL)
|
||||
#define HC_DEASSIGN_PIO_REGION BASE_HC_ID(HC_ID, HC_ID_PCI_BASE + 0x0CUL)
|
||||
|
||||
/* DEBUG */
|
||||
#define HC_ID_DBG_BASE 0x60UL
|
||||
|
Loading…
Reference in New Issue
Block a user